运行 在 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 但没有 yielddosomethingfunc 将继续而无需等待 downloadfunc 完成。但实际上行为是相同的(有或没有 yield)- "Do something else" 只会在 downloadfunc 完成下载后打印。

我在这里缺少什么?

为了受益于 Tornado 的异步,在某些时候必须 yielded 非阻塞函数。由于 downloadfunc 的代码都是阻塞的,因此 dosomethingfunc 在调用的函数完成之前不会取回控制权。

您的代码有几个问题:

所以 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