在Python2.7中,如果没有第三方包,如何实现异步请求
我想要的是标题。背景是我有数千个请求要发送到程序中一个非常慢的Restful接口,其中除请求外,所有第三方包都不允许导入 多线程和多处理的速度仅限于GIL和运行程序的4核计算机 我知道您可以通过生成器在Python2.7中实现一个不完整的协同路由,并生成关键字,但我如何才能使用不完整的协同路由功能执行数千个请求呢 例子在Python2.7中,如果没有第三方包,如何实现异步请求,python,asynchronous,python-requests,Python,Asynchronous,Python Requests,我想要的是标题。背景是我有数千个请求要发送到程序中一个非常慢的Restful接口,其中除请求外,所有第三方包都不允许导入 多线程和多处理的速度仅限于GIL和运行程序的4核计算机 我知道您可以通过生成器在Python2.7中实现一个不完整的协同路由,并生成关键字,但我如何才能使用不完整的协同路由功能执行数千个请求呢 例子 首先,你从一个错误的前提出发 多处理的速度根本不受GIL的限制 多处理的速度仅受CPU限制工作的内核数量的限制,而您的情况并非如此。异步对于CPU受限的工作根本不起作用,因此多
首先,你从一个错误的前提出发
- 多处理的速度根本不受GIL的限制
- 多处理的速度仅受CPU限制工作的内核数量的限制,而您的情况并非如此。异步对于CPU受限的工作根本不起作用,因此多处理将是异步的4倍,而不是更糟
- 多线程处理的速度只受CPU绑定代码的GIL限制,而您的GIL又不是
- 多线程的速度几乎不受内核数量的影响。如果您的代码是CPU绑定的,那么线程大部分会在单个内核上序列化。但是,异步在这里更糟糕,而不是更好
async
的原因并不是因为它解决了这些问题;事实上,这只会让情况变得更糟。主要的优点是,如果您有大量的工作人员几乎不做任何工作,那么您可以将大量的等待时间安排在协同路由上,这比大量的等待线程或进程要便宜得多。第二个优点是,您可以将选择器循环绑定到调度程序循环,并消除协调它们的一些开销
其次,首先不能将
请求
与asyncio
一起使用。它希望能够在套接字读取时阻止整个线程。有一个项目是围绕一个基于asyncio
的传输适配器重写它,但它没有完成就被放弃了
通常的解决方法是在线程中使用它,例如,使用run\u in\u executor
。但是,如果您正在做的唯一事情是请求
,那么构建事件循环只是为了将事情分派给线程池执行器是愚蠢的;直接使用执行器即可
第三,我怀疑您是否真的需要有数千个请求并行运行。当然,尽管细节取决于您的服务、网络或任何瓶颈,但拥有一个线程池(例如,12或64个并行运行的请求,其他数千个请求在后面排队)几乎总是更有效的 处理数千个并发连接(因此也是工作者)通常只需要在服务器上完成。有时,您必须在从大量不同服务聚合数据的客户端上执行此操作。但是,如果您只使用一个服务,那么多并发性几乎没有任何好处
第四,如果您真的希望在Python2中使用基于协同程序的事件循环,到目前为止最简单的方法是使用
gevent
或greenlets
或其他类似的库
是的,它们给你一个隐藏在你看不见的封面下的事件循环,以及一个“神奇”的协同程序,其中屈服发生在方法内部,比如socket.send
和Thread.join
,而不是通过wait
或yield from
显式可见,但好的一面是它们已经起作用了,事实上,这种魔力意味着它们可以处理请求
,而您构建的任何东西都不会
当然,您不想使用任何第三方库。在Stackless或PyPy上构建类似于greenlets的东西非常容易;为CPython构建它需要做更多的工作。然后,您仍然需要像gevent
那样进行所有的修补,使sockets
之类的库像魔术一样工作,或者围绕显式的greenlet重写请求
无论如何,如果您真的想在纯
yield
之上构建一个事件循环,您可以
在中,他列举了只使用yield
的协程事件循环的例子,以及使用显式蹦床来yield
的更好的例子和一个简单的网络驱动的例子。他甚至还编写了一个自动翻译程序,将代码从转换为Python3.1(当时还没有实现)
请注意,在蹦床上弹跳每一个屈服点都会降低效率。真的没办法。这是我们从该语言中获得收益的一个很好的部分原因
但这只是带有一点玩具网络的调度程序部分。您仍然需要集成一个选择器
循环,然后编写协同程序来替换所需的所有套接字
函数。考虑代码< > AcsiCIO <代码>多长时间,当他知道Python的内部和外部,并从中得到<代码>收益时,就可以建立GuDo……但是你可以窃取他的大部分设计,所以不会那么糟糕。不过,这将是一个很大的工作
(哦,Python 2中没有选择器
。如果你不关心Windows,那么从选择
模块中构建你需要的部分是非常容易的,但是如果你关心Windows,那就需要做很多工作。)
请记住,因为请求
与您的代码不兼容,所以您还需要重新实现大部分请求。或者,最好将aiohttp
从asyncio
移植到您的框架中
最后,我愿意给大家一个机会,结果不会像Python 3中的aiohttp
或Python 2中的gevent
上的requests
那样有效,或者只是<
url_list = ["https://www.example.com/rest?id={}".format(num) for num in range(10000)]
results = request_all(url_list) # do asynchronously