2014-05-22 69 views
0

我正在使用Tornado CurlAsyncHTTPClient。當我爲每個請求實例化相應的httpclient時,我的進程內存對於阻塞和非阻塞請求都在持續增長。如果我只有一個httpclient實例(tornado.httpclient.HTTPClient/tornado.httpclient.AsyncHTTPClient)並且重用它們,則不會發生此內存使用增長。進程內存增長巨大-Tornado CurlAsyncHTTPClient

另外如果我使用SimpleAsyncHTTPClient而不是CurlAsyncHTTPClient這種內存增長不會發生,無論我如何實例化。

下面是一個示例代碼再現此,

import tornado.httpclient 
import json 
import functools 

instantiate_once = False 
tornado.httpclient.AsyncHTTPClient.configure('tornado.curl_httpclient.CurlAsyncHTTPClient') 

hc, io_loop, async_hc = None, None, None 
if instantiate_once: 
    hc = tornado.httpclient.HTTPClient() 
    io_loop = tornado.ioloop.IOLoop() 
    async_hc = tornado.httpclient.AsyncHTTPClient(io_loop=io_loop) 

def fire_sync_request(): 
    global count 
    if instantiate_once: 
     global hc 
    if not instantiate_once: 
     hc = tornado.httpclient.HTTPClient() 
    url = '<Please try with a url>' 
    try: 
     resp = hc.fetch(url) 
    except (Exception,tornado.httpclient.HTTPError) as e: 
     print str(e) 
    if not instantiate_once: 
     hc.close() 

def fire_async_requests(): 
    #generic response callback fn 
    def response_callback(response): 
     response_callback_info['response_count'] += 1 
     if response_callback_info['response_count'] >= request_count: 
      io_loop.stop() 
    if instantiate_once: 
     global io_loop, async_hc 
    if not instantiate_once: 
     io_loop = tornado.ioloop.IOLoop() 
    requests = ['<Please add ur url to try>']*5 
    response_callback_info = {'response_count': 0} 
    request_count = len(requests) 
    global count 
    count +=request_count 
    hcs=[] 
    for url in requests: 
     kwargs ={} 
     kwargs['method'] = 'GET' 
     if not instantiate_once: 
      async_hc = tornado.httpclient.AsyncHTTPClient(io_loop=io_loop) 
     async_hc.fetch(url, callback=functools.partial(response_callback), **kwargs) 
     if not instantiate_once: 
     hcs.append(async_hc) 

    io_loop.start() 
    for hc in hcs: 
     hc.close() 
    if not instantiate_once: 
     io_loop.close() 

if __name__ == '__main__': 
    import sys 
    if sys.argv[1] == 'sync': 
     while True: 
      output = fire_sync_request() 
    elif sys.argv[1] == 'async': 
     while True: 
      output = fire_async_requests() 

這裏設置instantiate_once變量爲True,並且執行 蟒check.py同步或Python check.py異步。進程內存不斷增加

With instantiate_once = False,這不會發生。

此外如果我使用SimpleAsyncHTTPClient而不是CurlAsyncHTTPClient這種內存增長不會發生。

我有蟒2.7 /龍捲風2.3.2/pycurl(的libcurl/7.26.0的GnuTLS/20年2月12日的zlib/1.2.7的libidn/1.25 libssh2/1.4.2 librtmp/2.3)

我可以重現與最新的龍捲風相同的問題3.2

請幫我理解這種行爲並找出使用龍捲風作爲http庫的正確方法。

回答

1

HTTPClient和AsyncHTTPClient被設計爲可重複使用,所以它總是更有效,而不是一直重新創建它們。實際上,AsyncHTTPClient會嘗試神奇地檢測是否存在相同IOLoop上的現有AsyncHTTPClient,並使用該AsyncHTTPClient而不是創建新的。

儘管最好重用一個http客戶端對象,但不應該因爲你在這裏(只要你關閉它們)而泄漏來創建它們中的許多對象。這看起來像在pycurl中的錯誤:https://github.com/pycurl/pycurl/issues/182

+0

哦,明白了。我希望它能夠在我創建和關閉時正常工作。無論如何,我只會實例化一次,讓它重用並最終關閉它。非常感謝Ben。 – Ramyavjr

0

使用pycurl 7.19.5和這個技巧以避免內存泄漏:

你的旋風主文件:

tornado.httpclient.AsyncHTTPClient.configure("curl_httpclient_leaks_patched.CurlAsyncHTTPClientEx") 

curl_httpclient_leaks_patched.py

from tornado import curl_httpclient 

class CurlAsyncHTTPClientEx(curl_httpclient.CurlAsyncHTTPClient): 

    def close(self): 
     super(CurlAsyncHTTPClientEx, self).close() 
     del self._multi