你好吗?在
最近几天我经历了这样的麻烦,我似乎不能完全理解龙卷风发电机库。在
我有一段代码作为例子:
@gen.coroutine
def get(self, build_id=None):
status_query = self.get_query_arguments("status")
limit_query = self.get_query_arguments("limit")
results = [self._dummy() for i in range(15)]
yield results
def _dummy(self):
http_client = tornado.httpclient.AsyncHTTPClient()
return http_client.fetch("https://www.google.com", headers=self.headers, validate_cert=False)
正如我所想的,我的15个获取谷歌的请求应该几乎同时触发。 “结果”列表,应该是一个期货列表,然后,收益列表应该等待所有这些都完成。在
这确实发生了,但发出这些请求大约需要6秒,而且随着for循环范围的增加,请求量也在逐渐增加。在
他们不应该花同样的时间来准备吗?在
我错过什么了吗?在
非常感谢!在
AsyncHTTPClient的默认最大客户端数为10。当您启动15个请求时,其中10个请求立即开始,但其余5个请求必须等待其他请求完成才能开始。要开始更多并发请求,请将max_clients提升到更大的数目。See Tornado's documentation for details on configuring AsyncHTTPClient.
在编程中,这些是我们的主要限制:
在Python中,由于GIL,当涉及到CPU访问时,我们甚至受到了进一步的限制。对于趋向于多核(2、4、8或16)的现代计算机来说,我们的性能更差,因为这些处理器中的每一个都要慢一点。有关GIL的更多信息,请查看David Beazley's GIL talk和{a2}。在
为了绕过全局解释器锁,已经开发了几个回调风格的模块,比如Twisted、Tornado和asyncio。这些工作的方式是通过执行一些操作,当它们到达IO停止的点时,通常会产生屈服控制。在
例如,如果我正在向旋转的磁盘写入数据,也许我可以向磁盘写入100kb的数据,但是当我在等待所有这些信息被写入时,也许我可以在所有数据写入完毕之前执行1000次计算。在
或者,我可以每秒向一个webservice发出100个请求,但对每个请求执行计算只需0.0001秒。如果你看一张我花时间在哪里的图表,它会是这样的:
这些进程允许您交叉处理和读/写,方法是发送请求包,然后执行其他操作,然后在某个时刻返回以读取返回的包。在
像这样绑定IO,你可以看到一个相当大的加速,因为不是像这样:
^{pr2}$你可以得到这样的东西:
但是如果你的进程是CPU限制的,你不会看到任何加速(或者至少不会太快),因为你要花30秒来处理,而只有1秒在等待网络。在
在尝试异步方法之前,请给出标准的单线程方法,并查看1)它是否足够快;2)在网络/IO边界是否慢。在
对于Python,您可以很容易地使用line profiler,并且(如果还没有)分离出读、处理和写函数,并查看您花在哪里的时间。如果大部分时间都花在read函数上,那么是的,您应该可以看到异步方法带来的相当合理的加速。如果不是,异步只会减慢速度。在
相关问题 更多 >
编程相关推荐