考虑这个简短的片段:
import tornado
import tornado.websocket
import tornado.ioloop
import tornado.gen
import tornado.web
class NewWsHandler(tornado.websocket.WebSocketHandler):
async def on_message(self, message):
await self.write_message("echo " + message)
class OldWsHandler(tornado.websocket.WebSocketHandler):
@tornado.gen.coroutine
def on_message(self, message):
yield self.write_message("echo " + message)
app = tornado.web.Application([(r'/', OldWsHandler)])
app.listen(8080)
tornado.ioloop.IOLoop.current().start()
OldWsHandler
在Tornado中使用3.5之前的异步函数方式,它运行正常。但是,as the documentation states,最好使用PEP 0492来提高可读性和速度。
文档说:
只需使用
async def foo()
代替@gen.coroutine
装饰器的功能定义,而await
代替yield
。
所以我写了NewWsHandler
。但是,在发送websocket消息时,它会发出警告:
/usr/lib/python3.5/site-packages/tornado/websocket.py:417: RuntimeWarning: coroutine 'on_message' was never awaited callback(*args, **kwargs)
我真的不知道如何(正确)修复它。我尝试在tornado.web.asynchronous
中进行装饰,但假定HTTP verb method。所以在我覆盖finish()
(不允许websockets这样做)后,它似乎有点工作:
class NewWsHandler(tornado.websocket.WebSocketHandler):
def finish(self):
pass
@tornado.web.asynchronous
async def on_message(self, message):
await self.write_message("echo " + message)
但这仍然看起来很骇人听闻,似乎与文档相矛盾。这样做的正确方法是什么?
注意:我使用的是Python 3.5.1和Tornado 4.3。
答案 0 :(得分:5)
协程的调用方式与常规函数不同;因此,当子类化和重写方法时,您无法将基类中的常规方法更改为子类中的协程(除非基类明确指出这是正常的)。 WebSocketHandler.on_message
可能不是协程(从Tornado 4.3开始;将来可能会改变)。
相反,如果您需要在响应消息时执行异步操作,请将异步部分放在单独的函数中并使用IOLoop.current().spawn_callback
调用它。 (或者如果write_message
是您正在做的唯一异步事情,请同步调用它)
这在Tornado 4.5中发生了变化,WebSocketHandler.on_message
现在可以用作协程。请参阅http://www.tornadoweb.org/en/stable/releases/v4.5.0.html#tornado-websocket。