2016-07-14 71 views
1

你好吗?AsyncHTTPClient阻止我的龙卷风IOLoop

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

我有这样的一段代码,作为一个例子:

@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循环的范围而逐渐增加。

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

我错过了什么吗?

非常感谢!

+0

如果你的请求没有IO绑定,那么你不会看到太多的改变。 –

+0

你能解释我多一点吗? :) –

回答

2

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

+0

但是,正如它在我的例子中,将创建AsyncHTTPClient不同的情况下,每一个决策只是一个请求......难道我错了吗? –

+0

是 - 内部,AsyncHTTPClient对象共享请求中的一个队列。 –

+0

是的,我刚刚在文档中发现。那很棒。 Buuuut,我刚刚将max_clients增加到了50,并且仍然有相同的问题。随着我添加更多请求,时间依然在递增。 (不超过50限制) –

1

如果你的请求没有IO绑定,那么你不会看到太多的改变。 - Me

在编程这些是我们具有初级限制:

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

在Python中,由于GIL,我们甚至进一步限制了CPU访问。由于趋向于多核 - 2,4,8或16的计算机,我们甚至进一步瘫痪,因为通常是,这些处理器中的每一个都会慢一点。有关GIL的更多信息,请查看David Beazley's GIL talkLarry Hasting's GIL-ectomy

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

例如,如果我正在将数据写入旋转磁盘,也许我可以写入100kb的磁盘,但在等待所有信息写入时,或许我可以关闭并执行1,000次在所有数据写完之前进行计算。

或者,也许我可以让每秒100个请求Web服务,但是只需要我0.0001s执行我的计算为每个请求。如果你看的,我把我的时间它会是这个样子的图形:

#    
    #    
    #    
    #    
    #    
    #    
    #    
    #   # 
-------------------------- 
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多岁做处理只有1秒做任何形式的等待网络。

尝试异步方法之前,给标准的单线程方式,看看1),如果它的速度不够快; 2)如果在网络/ IO边界很慢。

您可以轻松使用类似Python的line profiler之类的东西,并且(如果还没有的话)分离出读取,处理和写入功能,并查看您花费的时间。如果你花大部分的在读功能的时间,那么是的,你应该看到从异步方法相当合理的增速。如果不是,异步会让你放慢速度。

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

+0

回答 – desertkun