我正在使用Tornado CurlAsyncHTTPClient。当我为每个请求实例化相应的httpclients时,我的进程内存对于阻塞和非阻塞请求都在不断增长。如果我只有一个httpclients实例(tornado.httpclient.HTTPClient / tornado.httpclient.AsyncHTTPClient)并重用它们,则不会发生这种内存使用增长。
此外,如果我使用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,然后执行 python check.py sync或python check.py async。进程内存不断增加
使用instantiate_once = False时,不会发生这种情况。
此外,如果我使用SimpleAsyncHTTPClient而不是CurlAsyncHTTPClient,则不会发生这种内存增长。
我有python 2.7 / tornado 2.3.2 / pycurl(libcurl / 7.26.0 GnuTLS / 2.12.20 zlib / 1.2.7 libidn / 1.25 libssh2 / 1.4.2 librtmp / 2.3)
我可以用最新的龙卷风3.2重现同样的问题
请帮助我理解这种行为并找出使用龙卷风作为http库的正确方法。
答案 0 :(得分:1)
HTTPClient和AsyncHTTPClient旨在重用,因此不再一直重新创建它们总是更有效率。事实上,AsyncHTTPClient将尝试神奇地检测同一个IOLoop上是否存在现有的AsyncHTTPClient,并使用它而不是创建一个新的。
但是,即使重用一个http客户端对象更好,但它不应该泄漏以创建其中的许多对象(只要您正在关闭它们) )。这看起来像是pycurl中的一个错误:https://github.com/pycurl/pycurl/issues/182
答案 1 :(得分:0)
使用pycurl 7.19.5和这个hack来避免内存泄漏:
您的Tornado主文件:
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