AsyncHTTPClient阻止了我的Tornado IOLoop

时间:2016-07-14 16:34:11

标签: python tornado coroutine

你好吗?

我在最后几天经历过这个麻烦,我似乎无法完全理解龙卷风基因库。

我有这段代码,例如:

@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循环的范围,它会逐渐增长。

他们不应该在同一时间准备好吗?

我错过了什么吗?

非常感谢!

2 个答案:

答案 0 :(得分:2)

AsyncHTTPClient的默认max_clients为10.当您发起15个请求时,其中10个立即开始,但其余5个必须等待其他请求完成才能开始。要开始更多并发请求,请将max_clients提升到更大的数字。 See Tornado's documentation for details on configuring AsyncHTTPClient.

答案 1 :(得分:1)

  

如果您的请求不是IO绑定,那么您将看不到太多变化。 - Me

在编程中,这些是我们的主要限制:

  • CPU(每秒可发生的计算次数)
  • 处理器中的缓存访问
  • RAM访问
  • 磁盘访问
  • 网络访问

在Python中,由于GIL,我们在CPU访问方面甚至受到进一步的限制。随着现代计算机倾向于多核--2,4,8或16 - 我们甚至进一步削弱了 1 ,因为通常每个那些处理器会慢一点。有关GIL的更多信息,请查看David Beazley's GIL talkLarry Hasting's GIL-ectomy

为了绕过Global Interpreter Lock,开发了几个回调式模块,如Twisted,Tornado和asyncio。这些工作的方式是通过执行某些操作,当它们到达IO停止点时通常会产生控制。

例如,如果我将数据写入旋转磁盘,也许我可以将100kb写入磁盘,但是当我等待写入所有这些信息时,也许我可以进行1000次计算在所有数据完成之前。

或者,也许我可以每秒向Web服务发出100个请求,但是每个请求只执行我的计算需要0.0001秒。如果你看一下我花时间在哪里的图表,它会看起来像这样:

    #            
    #            
    #            
    #            
    #            
    #            
    #            
    #           #
--------------------------
 reading    processing

这些进程允许你做的是交错处理和读/写,通过发送请求数据包,然后做其他事情,然后在某些时候回来读取返回的数据包。

像这样的IO绑定,你可以看到相当大的加速,因为而不是看起来像这样:

 start    end start     end
--|--------|----|--------|------
 t=0      t=5  t=6      t=11

你可以得到这样的东西:

     start      end
 start|     end  |
--|---|------|---|-
 t=0 t=1    t=5  t=6

如果您的进程受CPU限制,您将不会看到任何加速(或至少不会太多),因为您花费30多秒进行处理而只有1s做任何类型等待网络。

在尝试异步方法之前,先给出标准的单线程方法,然后看1)它是否足够快,2)是否在网络/ IO边界处慢。

您可以轻松地使用像line profiler这样的Python,并且(如果还没有)将您的读取,处理和写入功能分开,并查看您在哪里花时间。如果你大部分时间都花在阅读功能上,那么你应该从异步方法中看到一个相当合理的加速。如果没有,异步只会让你失望。

  

1 老实说,这并不是那么糟糕,除非你有超速的关键。然后你应该使用cffi或其他东西来获取速度关键部分并将它们转储到C.你做了找出哪些部分是阻止,对吗?