问题描述
考虑这个简短的片段:
导入龙卷风导入 tornado.websocket导入 tornado.ioloop进口龙卷风.gen导入 tornado.web类 NewWsHandler(tornado.websocket.WebSocketHandler):async def on_message(self, message):await self.write_message("echo " + message)类 OldWsHandler(tornado.websocket.WebSocketHandler):@tornado.gen.coroutinedef 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 中使用了 pre-3.5 的异步函数方式,并且它工作正常.但是,如文档所述,它为了可读性和速度,最好使用 PEP 0492.
文档说:
只需使用 async def foo()
代替带有 @gen.coroutine
装饰器的函数定义,并使用 await
代替产量
.
所以我写了NewWsHandler
.但是,当发送 websocket 消息时,它会引发警告:
我真的不知道如何(正确)修复它.我尝试在 tornado.web.asynchronous
中装饰它,但这假设 HTTP 动词方法.所以在我覆盖 finish()
之后(不允许 websockets 这样做),它似乎有点工作:
class NewWsHandler(tornado.websocket.WebSocketHandler):定义完成(自我):经过@tornado.web.asynchronousasync def on_message(self, message):await self.write_message("echo " + message)
但这看起来仍然很黑客,并且似乎与文档相矛盾.这样做的正确方法是什么?
注意:我使用的是 Python 3.5.1 和 Tornado 4.3.
协程的调用方式与常规函数不同;因此,在子类化和覆盖方法时,您不能将基类中的常规方法更改为子类中的协程(除非基类明确表示这是可以的).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.
Consider this short snippet:
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
uses the pre-3.5 way of doing asynchronous functions in Tornado, and it works fine. However, as the documentation states, it is preferred to use PEP 0492 for readability and speed.
The documentation says:
So I wrote NewWsHandler
. However, when sending a websocket message, it raises a warning:
/usr/lib/python3.5/site-packages/tornado/websocket.py:417: RuntimeWarning: coroutine 'on_message' was never awaited callback(*args, **kwargs)
I don't really know how to (properly) fix it. I tried decorating it in tornado.web.asynchronous
, but that assumes a HTTP verb method. So after I override finish()
(websockets are not allowed to do that), it seems to be kind of working:
class NewWsHandler(tornado.websocket.WebSocketHandler):
def finish(self):
pass
@tornado.web.asynchronous
async def on_message(self, message):
await self.write_message("echo " + message)
But this still looks hackerish, and seems to be contradicting the documentation. What is the right way of doing this?
Note: I am using Python 3.5.1 and Tornado 4.3.
Coroutines are called differently than regular functions; therefore when subclassing and overriding methods you cannot change a regular method in the base class into a coroutine in your subclass (unless the base class specifically says this is OK). WebSocketHandler.on_message
may not be a coroutine (as of Tornado 4.3; this may change in the future).
Instead, if you need to do something asynchronous in response to a message, put the asynchronous parts in a separate function and call it with IOLoop.current().spawn_callback
. (or if write_message
is the only async thing you're doing, just call it synchronously)
Update
This changed in Tornado 4.5, WebSocketHandler.on_message
can now be used as a coroutine. See http://www.tornadoweb.org/en/stable/releases/v4.5.0.html#tornado-websocket.
这篇关于如何在 Tornado 中为 websockets 使用 Python 3.5 风格的异步和等待?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!