运行 在 python 龙卷风上并行运行
run function parallel on python tornado
我目前正在 python3
中开发 tornado
框架(仍是初学者),并且我有一个我想 运行 在后台使用的功能。更准确地说,该函数的任务是下载一个大文件(逐块),并可能在下载每个块后做更多的事情。但是调用函数不应该等待下载函数完成,而应该继续执行。
这里有一些代码示例:
@gen.coroutine
def dosomethingfunc(self, env):
print("Do something")
self.downloadfunc(file_url, target_path) #I don't want to wait here
print("Do something else")
@gen.coroutine
def downloadfunc(self, file_url, target_path):
response = urllib.request.urlopen(file_url)
CHUNK = 16 * 1024
with open(target_path, 'wb') as f:
while True:
chunk = response.read(CHUNK)
if not chunk:
break
f.write(chunk)
time.sleep(0.1) #do something after a chunk is downloaded - sleep only as example
我在 Whosebug 上阅读了这个答案并尝试使用它。
实际上我认为如果我使用 @gen.coroutine
但没有 yield
则 dosomethingfunc
将继续而无需等待 downloadfunc
完成。但实际上行为是相同的(有或没有 yield)- "Do something else
" 只会在 downloadfunc
完成下载后打印。
我在这里缺少什么?
为了受益于 Tornado 的异步,在某些时候必须 yielded
非阻塞函数。由于 downloadfunc
的代码都是阻塞的,因此 dosomethingfunc
在调用的函数完成之前不会取回控制权。
您的代码有几个问题:
time.sleep
正在阻塞,请改用 tornado.gen.sleep
,
- urllib 的
urlopen
被阻塞,使用 tornado.httpclient.AsyncHTTPClient
所以 downloadfunc
可能看起来像:
@gen.coroutine
def downloadfunc(self, file_url, target_path):
client = tornado.httpclient.AsyncHTTPClient()
# below code will start downloading and
# give back control to the ioloop while waiting for data
res = yield client.fetch(file_url)
with open(target_path, 'wb') as f:
f.write(res)
yield tornado.gen.sleep(0.1)
要通过流(按块)支持实现它,您可能需要这样做:
# for large files you must increase max_body_size
# because deault body limit in Tornado is set to 100MB
tornado.web.AsyncHTTPClient.configure(None, max_body_size=2*1024**3)
@gen.coroutine
def downloadfunc(self, file_url, target_path):
client = tornado.httpclient.AsyncHTTPClient()
# the streaming_callback will be called with received portion of data
yield client.fetch(file_url, streaming_callback=write_chunk)
def write_chunk(chunk):
# note the "a" mode, to append to the file
with open(target_path, 'ab') as f:
print('chunk %s' % len(chunk))
f.write(chunk)
现在您可以在 dosomethingfunc
中调用它而无需 yield
,函数的其余部分将继续。
编辑
不支持(公开)修改块大小,无论是从服务器端还是客户端。你也可以看看 https://groups.google.com/forum/#!topic/python-tornado/K8zerl1JB5o
我目前正在 python3
中开发 tornado
框架(仍是初学者),并且我有一个我想 运行 在后台使用的功能。更准确地说,该函数的任务是下载一个大文件(逐块),并可能在下载每个块后做更多的事情。但是调用函数不应该等待下载函数完成,而应该继续执行。
这里有一些代码示例:
@gen.coroutine
def dosomethingfunc(self, env):
print("Do something")
self.downloadfunc(file_url, target_path) #I don't want to wait here
print("Do something else")
@gen.coroutine
def downloadfunc(self, file_url, target_path):
response = urllib.request.urlopen(file_url)
CHUNK = 16 * 1024
with open(target_path, 'wb') as f:
while True:
chunk = response.read(CHUNK)
if not chunk:
break
f.write(chunk)
time.sleep(0.1) #do something after a chunk is downloaded - sleep only as example
我在 Whosebug 上阅读了这个答案并尝试使用它。
实际上我认为如果我使用 @gen.coroutine
但没有 yield
则 dosomethingfunc
将继续而无需等待 downloadfunc
完成。但实际上行为是相同的(有或没有 yield)- "Do something else
" 只会在 downloadfunc
完成下载后打印。
我在这里缺少什么?
为了受益于 Tornado 的异步,在某些时候必须 yielded
非阻塞函数。由于 downloadfunc
的代码都是阻塞的,因此 dosomethingfunc
在调用的函数完成之前不会取回控制权。
您的代码有几个问题:
time.sleep
正在阻塞,请改用tornado.gen.sleep
,- urllib 的
urlopen
被阻塞,使用tornado.httpclient.AsyncHTTPClient
所以 downloadfunc
可能看起来像:
@gen.coroutine
def downloadfunc(self, file_url, target_path):
client = tornado.httpclient.AsyncHTTPClient()
# below code will start downloading and
# give back control to the ioloop while waiting for data
res = yield client.fetch(file_url)
with open(target_path, 'wb') as f:
f.write(res)
yield tornado.gen.sleep(0.1)
要通过流(按块)支持实现它,您可能需要这样做:
# for large files you must increase max_body_size
# because deault body limit in Tornado is set to 100MB
tornado.web.AsyncHTTPClient.configure(None, max_body_size=2*1024**3)
@gen.coroutine
def downloadfunc(self, file_url, target_path):
client = tornado.httpclient.AsyncHTTPClient()
# the streaming_callback will be called with received portion of data
yield client.fetch(file_url, streaming_callback=write_chunk)
def write_chunk(chunk):
# note the "a" mode, to append to the file
with open(target_path, 'ab') as f:
print('chunk %s' % len(chunk))
f.write(chunk)
现在您可以在 dosomethingfunc
中调用它而无需 yield
,函数的其余部分将继续。
编辑
不支持(公开)修改块大小,无论是从服务器端还是客户端。你也可以看看 https://groups.google.com/forum/#!topic/python-tornado/K8zerl1JB5o