Python:通过选择.epoll()

2024-09-30 20:29:56 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个面向事件的服务器,它已经使用了select.epoll()。在

应该解决异步URL(现在应该解决一个新的获取URL的要求)。在

到目前为止,我一直使用请求库,而且我总是同步使用它,而不是异步的。在

如何将请求库(或不同的urllib)与linuxepoll结合使用?在

请求库文档对此有一个注释,但是只提到了异步框架(没有选择.epoll()):http://docs.python-requests.org/en/master/user/advanced/#blocking-or-non-blocking

我没有结婚选择.epoll(). 到现在为止还有效。如果可行的话,我可以用不同的解决方案。在

背景:更大的问题是“我应该使用吗选择.epoll()或python所拥有的众多异步框架之一?”。但StackOverflow的问题不能太宽泛。这就是为什么这个问题集中在“通过选择.epoll()". 如果你对更大的问题有什么建议,请留言。在

如果您好奇,这个问题是我在业余时间开发的一个小项目所需要的:https://github.com/guettli/ipo(IPO是一个基于PostgreSQL的开源异步作业队列)


Tags: 文档org服务器框架httpurldocs面向
3条回答

上面的要点是正确的,从技术上讲,对于多路复用I/O(如select()epoll())的阻塞调用以及BSD/iOS、Windows变体,您无法做到这一点。这些调用允许超时规范,因此您可以通过在短时间间隔内重复轮询,然后将工作从主线程传递给异步处理程序来接近。在这种情况下,读取是在主线程上完成的,多个读取可以表示它们准备好了,而主线程主要用于该任务。在

如果问题的规模是小到中,那么没有什么能比epoll()...read()甚至select()...read()强。如果您的问题(读取通道的数量)是在小方面。所以我建议你考虑一下——从主线程上尽可能多地处理请求。在

如果您正在寻找一个异步解决方案,那么您最好的选择之一是grequests库,以便于使用和提高性能。要获得一个想法,请运行以下客户机-服务器对。请注意,在这里使用tornado是无关的,而且只在服务器端,而您关心的是客户端。在

试试这个-性能的差别是白天和黑夜。在

您的解决方案由客户端.py类,它使用grequests异步发出get()请求。在

服务器.py

from tornado import (httpserver, options,
                     ioloop, web, gen)
import time

import ujson as json
from collections import defaultdict

class Check(web.RequestHandler):

    @gen.coroutine
    def get(self):
        try:
            data = int(self.get_argument('data'))
        except ValueError:
            raise web.HTTPError(400, reason='Invalid value for data')

        delay = 100
        start = time.time()
        print('Processed: {!r}'.format(data))

       yield gen.Task(ioloop.IOLoop.instance().add_timeout, start + delay / 1000.)

        self.write('.')
        end = time.time()
        self.finish()


if __name__ == '__main__':
    port = 4545

    application = web.Application([
        (r'/get', Check)
        ])

    http_server = httpserver.HTTPServer(application)
    http_server.listen(port)
    print('Listening on port: {}'.format(port))
    ioloop.IOLoop.instance().start()

客户端.py

^{pr2}$

这是一个真正的异步解决方案,或者说是在CPython/python中最接近的解决方案。没有使用轮询器。在

我们在做武器的时候,总是基于高性能来选择武器情况。所以答案还是太宽泛了。在

但你更大的问题更简单只有一个IO绑定程序适合异步。在

epoll和异步的目的是什么?避免CPU等待IO没什么。CPU等待IO块,IO块是因为没有可读取的数据或没有可写入的空间。在

引入缓冲区来降低系统的功耗打电话。什么时候在流上调用read,实际上是从缓冲区读取

Select或epoll是非阻塞的忙轮询(epoll通过中断底层实现)

while true {
  for i in stream[]{
    if i has data
          read until unavailable
    }
}

这很傻,所以有select和epoll。 每次你从缓冲区读取数据,都有数据在等着你,这是高速IO,那么epoll/select就是你的最佳选择选择。还有当缓冲区总是空的时候,它是一个慢流,IO绑定,异步非常适合这种情况。在

我不太了解异步,对我来说,这只是内部的软中断和大量的回调。在

如何将请求库(或不同的urllib)与linuxepoll结合使用?在

不幸的是,除非在构建这样一个库时考虑到了这种集成,否则您不能这样做。epoll,以及选择/poll/kqueue等都是I/O多路复用系统调用,需要围绕其构建整体程序架构。在

简单地说,一个典型的程序结构可以归结为

  • 你需要有一堆文件描述符(在你的例子中是非阻塞模式的套接字)
  • 在一个或多个描述符上发生指定事件之前,系统调用(manepoll_wait,如果epoll)会阻塞
  • 返回I/O可用描述符的信息

在此之后,外部代码的工作就是处理这些描述符,即计算出有多少数据可用,调用一些回调等

如果库使用常规阻塞套接字,则并行化它的唯一方法是使用线程/进程 这里有一个关于这个主题的很好的article,示例使用C,这很好,因为它更容易理解引擎盖下实际发生的事情

异步框架和请求库

让我们看看有什么建议here

If you are concerned about the use of blocking IO, there are lots of projects out there that combine Requests with one of Python's asynchronicity frameworks. Some excellent examples are requests-threads, grequests, and requests-futures).

请求线程使用线程

grequests-与gevent集成(这是另一个故事,见下文)

请求未来事实上也是线程/进程

它们都与真正的异步性无关

我应该用吗选择.epoll()或python拥有的众多异步框架之一

请注意,epolllinux特有的beast,它无法工作,即在具有不同机制的OS X上,称为kqueue。当你在写一个通用的工作队列时,这似乎不是一个好的解决方案。在

现在回到python。您可以选择以下选项:

线程/进程/同期期货-不太可能,因为你的应用程序是典型的C10K服务器

epoll/kqueue-你必须自己做所有事情。在获取httpurl的情况下,您不仅需要处理HTTP/ssl,还需要处理异步DNS解析。还可以考虑使用提供一些基本基础设施的asyncore[]

twisted/tornado基于回调的框架,已经为您完成了所有底层工作

gevent-如果您要重用现有的块库(urllib、requests等)并同时使用python2.x和python3.x,那么您可能会喜欢这样的解决方案。对于一个像你这样大小的应用程序,它可能没问题,但我不会把它用于任何更大的,应该是坚如磐石和运行在prod

异步

This module provides infrastructure for writing single-threaded concurrent code using coroutines, multiplexing I/O access over sockets and other resources, running network clients and servers, and other related primitives

它有你可能需要的一切。 还有很多库使用流行的RDBMs和http https://github.com/aio-libs

但是它缺乏对python2.x的支持,有ports到python2.x的asyncio,但不确定它们有多稳定

最后

因此,如果我可以牺牲python2.x,我个人会选择asyncio和相关的库

如果您真的需要Python2.x,请根据所需的稳定性和假定的峰值负载使用上述方法之一

相关问题 更多 >