我想要的是标题。背景是我有成千上万的请求要发送到程序中一个非常慢的Restful接口,在该接口中,除 requests 之外,所有不允许软件包都不允许导入。 >
多线程和多进程的速度仅限于GIL和将在其中运行程序的4核计算机。
我知道您可以通过生成器并生成关键字在Python 2.7中实现不完整的协程,但是我如何才能使用不完整的协程功能来执行数千个请求呢?
url_list = ["https://www.example.com/rest?id={}".format(num) for num in range(10000)]
results = request_all(url_list) # do asynchronously
答案 0 :(得分:1)
首先,您从错误的前提开始。
人们使用async
的原因不是因为它可以解决所有这些问题;实际上,这只会使他们变得更糟。主要优点是,如果您有大量的工人几乎不做任何工作,则可以比一吨的等待线程或进程更便宜地调度一堆等待协程。第二个优点是,您可以将选择器循环与调度程序循环绑定,并消除协调它们的一些开销。
第二,首先不能将requests
与asyncio
一起使用。它期望能够在套接字读取时阻止整个线程。有一个项目要围绕基于asyncio
的传输适配器来重写它,但是它没有完成就被废弃了。
通常的解决方法是在线程中使用它,例如与run_in_executor
一起使用。但是,如果您唯一要做的事情是requests
,那么建立一个仅将事件分派给线程池执行程序的事件循环是很愚蠢的;只需直接使用执行程序即可。
第三,我怀疑您实际上是否需要并行运行数千个请求。尽管详细信息当然取决于您的服务或网络或瓶颈,但拥有一个线程池可以并行运行(例如,并行运行12或64个请求,而其他数千个在它们后面排队)几乎总是更有效的
处理成千上万的并发连接(以及工作线程)通常只需要在服务器上完成即可。有时,您必须在聚合来自大量不同服务的数据的客户端上执行此操作。但是,如果您只使用一种服务,那么这么多的并发几乎永远不会有任何好处。
第四,如果您确实确实希望在Python 2中使用基于协程的事件循环,到目前为止,最简单的方法是使用gevent
或greenlets
或其他此类库。
是的,它们为您提供了一个事件循环,隐藏在您看不见的幕后,以及“神奇”的协程,其中,屈服发生在socket.send
和Thread.join
之类的方法中,而不是显式的可以在await
或yield from
上看到,但好的一面是它们已经可以工作了,实际上,魔术意味着它们可以在requests
上工作,而您构建的任何东西都不会。>
当然,您不想使用任何第三方库。在Stackless或PyPy之上自己构建类似greenlets
的东西非常容易;为CPython构建它需要做很多工作。然后,您仍然必须完成gevent
所做的所有猴子补丁操作,以使sockets
之类的库像魔术一样工作,或者在显式的greenlet周围重写requests
。
无论如何,如果您真的想仅在普通yield
上构建事件循环,就可以。
在Greg Ewing's original papers on why Python needed to add yield from
中,他提供了一个仅包含yield
的协程事件循环的示例,以及一个更好的示例,该示例使用显式蹦床yield
进行了一个简单的网络驱动示例。他甚至从yield from
到Python 3.1的代码中编写了一个自动翻译器。
请注意,必须从蹦床上弹尽所有力量,否则事情的效率就会大大降低。真的没有办法解决。这是我们使用yield from
语言的一个很好的原因。
但这只是带有玩具网络的调度程序部分。您仍然需要集成selectors
循环,然后编写协程以替换所需的所有socket
函数。考虑一下asyncio
花费Guido的时间,当他从内到外都了解Python并可以使用yield from
时……但是您可以窃取他的大部分设计,因此它不会完全那不好。尽管如此,这仍然需要大量工作。
(哦,而且您在Python 2中没有selectors
。如果您不关心Windows,可以很容易地从select
模块中构建所需的部分,但是如果您确实关心Windows,则还有很多工作要做。)
请记住,由于requests
无法与您的代码一起使用,因此您还需要重新实现大部分 it 。或者,也许更好,将aiohttp
从asyncio
移植到您的框架。
最后,我很乐意为您提供一个结果,即结果的效率不会像Python 3中的aiohttp
或{{1} {1}}(在Python 2中),或者只是requests
在任一线程池中。
当然,您将成为世界上唯一使用它的人。 gevent
有数百个bug可以在requests
和stdlib之间进行修复,这些错误仅是由于数十位早期采用者(包括对此类专家很认真的人)对其进行抨击而被发现。并且asyncio
,tulip
,requests
等都被成千上万台服务器使用,这些服务器处理着价值数十亿美元的业务,因此,您将受益于所有发现错误并需要修复的人们。无论您构建哪种产品,几乎都肯定不会像任何一种解决方案那样可靠。
所有这些对于您可能仍然需要移植到Python 3的事情而言,因为Python 2的生命周期不到一年半,并且发行版和第三方库已经脱离它。举一个相关的例子,aiohttp
3.0将至少需要Python 3.5。如果您想坚持使用Python 2.7,那么将永远坚持使用gevent
2.1。