当您有一些与异步事件循环不兼容的阻塞任务时,您必须将其放在单独的线程中。
如果您要拥有无限数量的阻塞任务,则需要使用线程池。
无论哪种方式,您都希望有一个包装异步任务来阻止来自线程任务的通知。
最简单的方法是使用像tornado-threadpool这样的预构建库。* 然后,您只需执行以下操作:
class LongHandler(tornado.web.RequestHandler):
@thread_pool.in_thread_pool
def long_time_function(self, callback):
time.sleep(5)
callback("foo")
如果你想自己做,这个要点展示了一个你必须做的例子——或者,当然,各种 Tornado 线程池库的源代码可以作为示例代码。
请记住 Python GIL 的局限性:如果您的后台任务受 CPU 限制(并且大部分工作在 Python 中完成,而不是在像 numpy 那样释放 GIL 的 C 扩展中),您必须将它放在单独的过程。快速搜索 Tornado 进程池库并没有找到那么多不错的选择,但是在 Python 中使线程池代码适应进程池代码通常非常容易。**
* 请注意,我并不是特别推荐该库;这只是谷歌搜索中出现的第一件事,一眼看去,它看起来可用且正确。
** 它通常就像concurrent.futures.ThreadPoolExecutor
用concurrent.futures.ProcessPoolExecutor
或multiprocessing.dummy.Pool
替换一样简单multiprocessing.Pool
。唯一的诀窍是确保所有任务参数和返回值都小且可腌制。