【问题标题】:How to use Python 3.5 style async and await in Tornado for websockets?如何在 Tornado 中为 websockets 使用 Python 3.5 风格的异步和等待?
【发布时间】:2016-02-21 22:20:16
【问题描述】:

考虑一下这个简短的 sn-p:

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 使用 3.5 之前的方式在 Tornado 中执行异步函数,并且运行良好。但是,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:从未等待协程'on_message' 回调(*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。

【问题讨论】:

    标签: python websocket tornado


    【解决方案1】:

    协程的调用方式与常规函数不同;因此,当子类化和覆盖方法时,您不能将基类中的常规方法更改为子类中的协程(除非基类明确表示可以)。 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

    【讨论】:

    • 有什么方法可以查询数据库(异步)以响应 websocket 消息吗?像result = await query(...) 这样的东西?我似乎找不到真正的好方法来做到这一点。 (除了我的问题中的“黑客”)。
    • 一旦你产生了一个单独的回调,你可以做任何你想做的事情。您只需要小心处理异常,因为此处引发的任何异常都不会通过 on_message 并影响 websocket 连接。另请注意,在前一条消息完成之前可能会出现另一条消息;为避免这种情况,您可能希望在 on_open() 中生成回调并使用队列与其通信。
    猜你喜欢
    • 2013-08-23
    • 2017-11-10
    • 1970-01-01
    • 2019-07-01
    • 2020-07-11
    • 1970-01-01
    • 1970-01-01
    • 2020-09-11
    • 1970-01-01
    相关资源
    最近更新 更多