Python2.7中Tornado@asynchronous处理器配合futures挂起原因咨询
嘿,来聊聊你遇到的这个Tornado异步问题
首先,你的问题确实和Python 2.7的futures包与Tornado的兼容性脱不了干系,同时Windows的线程模型也在其中推波助澜了一把。
为啥Python2.7下@asynchronous的处理器会挂起?
Python 2.7里的futures是concurrent.futures的向后移植版本,但它的Future类和Python3原生的并不是完全一致的——尤其是在线程回调的调度逻辑这块。
看你的代码,当ThreadPoolExecutor的任务跑完后,add_done_callback会在工作线程里执行那个lambda函数。而在Python2.7的futures环境下,Tornado的IOLoop.instance().add_callback可能因为线程间的GIL交互、信号机制差异,导致回调根本没被正确注册到主IOLoop的事件循环里。
再加上Windows的线程模型(比如没有fork支持,线程调度方式和Linux/macOS不一样),工作线程的回调信号可能压根没法被主IOLoop捕获,结果就是callback方法永远不会被调用,请求自然就一直挂着了。
怎么修复Python2.7下的@asynchronous版本?
你可以调整回调的注册方式,确保Tornado的IOLoop能准确接到任务完成的信号。比如换成IOLoop.current()替代IOLoop.instance(),并且显式保证回调在主线程执行:
from tornado.ioloop import IOLoop from functools import partial def callback(self, future): print("Resolviendo el future") self.write(future.result()) self.finish() @tornado.web.asynchronous def get(self): print ("Llamando función que bloquea") # 显式获取当前IOLoop(别用instance,current更可靠) current_ioloop = IOLoop.current() def done_callback(future): # 强制把回调丢回主IOLoop线程执行 current_ioloop.add_callback(lambda: self.callback(future)) self.executor.submit(partial(blocking_function, 10)).add_done_callback(done_callback) print ("Saliendo de función que bloquea")
不过说实话,更省心的方式是直接用你已经验证过的gen.coroutine——这是Tornado官方推荐的异步写法,代码简洁还兼容性拉满:
@tornado.gen.coroutine def get(self): print ("Llamando función que bloquea") result = yield self.executor.submit(blocking_function, 10) self.write(result) print ("Saliendo de función que bloquea")
最后总结下
- Python2.7的
futures包和Python3原生的concurrent.futures存在细微的兼容性差异,核心在Future回调的线程调度上; - Windows的线程模型会放大这种差异,导致回调无法被主IOLoop捕获;
- 优先用
gen.coroutine替代@asynchronous,既省心又不容易踩坑;如果非得用@asynchronous,记得用IOLoop.current()来注册回调,确保它跑在主线程里。
内容的提问来源于stack exchange,提问作者yorodm
相关产品推荐
相关产品推荐

