如何在 Tornado 中为 websockets 使用 Python 3.5 风格的异步和等待? [英] How to use Python 3.5 style async and await in Tornado for websockets?

查看:29
本文介绍了如何在 Tornado 中为 websockets 使用 Python 3.5 风格的异步和等待?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑这个简短的片段:

导入龙卷风导入 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 消息时,它会引发警告:

<前>/usr/lib/python3.5/site-packages/tornado/websocket.py:417: RuntimeWarning: coroutine 'on_message' 从未等待回调(*args,**kwargs)

我真的不知道如何(正确)修复它.我尝试在 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:

Simply use async def foo() in place of a function definition with the @gen.coroutine decorator, and await in place of yield.

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 风格的异步和等待?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆