如何在 Tornado 中使用 Python 3.5 风格的异步和等待进行 websockets?

How to use Python 3.5 style async and await in Tornado for websockets?

提问人:Evert Heylen 提问时间:2/22/2016 最后编辑:Evert Heylen 更新时间:4/14/2018 访问量:5068

问:

请看这个简短的片段:

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 之前的异步函数方式,效果很好。但是,正如文档所述,最好使用 PEP 0492 以提高可读性和速度。

文档说:

只需使用装饰器代替函数定义,并代替 .async def foo()@gen.coroutineawaityield

所以我写了.但是,在发送 websocket 消息时,它会引发警告:NewWsHandler

/usr/lib/python3.5/site-packages/tornado/websocket.py:417: RuntimeWarning: coroutine 'on_message' was never awaited
  callback(*args, **kwargs)

我真的不知道如何(正确)修复它。我尝试用 来装饰它,但这假设使用 HTTP 动词方法。因此,在我覆盖(不允许 websockets 这样做)之后,它似乎有点工作:tornado.web.asynchronousfinish()

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。

蟒蛇 websocket 龙卷风

评论


答:

5赞 Ben Darnell 2/22/2016 #1

协程的调用方式与常规函数不同;因此,在子类化和重写方法时,不能将基类中的常规方法更改为子类中的协程(除非基类明确表示这是可以的)。 可能不是协程(从 Tornado 4.3 开始;这将在未来发生变化)。WebSocketHandler.on_message

相反,如果需要对消息执行异步操作,请将异步部分放在单独的函数中,并使用 调用它。(或者,如果这是您正在执行的唯一异步操作,请同步调用它)IOLoop.current().spawn_callbackwrite_message


更新

这在 Tornado 4.5 中发生了变化,现在可以用作协程。请参见 http://www.tornadoweb.org/en/stable/releases/v4.5.0.html#tornado-websocketWebSocketHandler.on_message

评论

0赞 Evert Heylen 2/23/2016
那么,有没有办法(异步)查询数据库以响应 websocket 消息?像这样的东西 ?我似乎找不到一个真正好的方法。(除了我问题中的“黑客”)。result = await query(...)
1赞 Ben Darnell 2/23/2016
一旦你生成了一个单独的回调,你就可以做任何你想做的事。您只需要小心异常处理,因为此处引发的任何异常都不会传递并影响 websocket 连接。另请注意,在前一条消息完成之前,可能会有另一条消息传入;以避免这种情况,您可能希望生成回调并使用 Queue 与之通信。on_messageon_open()