Tornado WebSocketHandler 可以异步接收消息吗?

Can a Tornado WebSocketHandler receive messages asynchronously?

在 python 方面,我创建了一个 WebSocketHandler

from tornado import gen
from tornado.escape import json_decode
from tornado.websocket import WebSocketHandler

class Echo(WebSocketHandler):
    ...
    @gen.coroutine
    def on_message(self, message):
        message = json_decode(message)
        response = yield self.do_echo(message)
        self.write_message(response)

    @gen.coroutine
    def do_echo(self, message):
        # emulate long, blocking call
        sleep(randint(0, 5))
        raise gen.Return(message)

在 javascript 方面,我同时启动多个客户端(不同的浏览器):

var ws = new WebSocket('ws://localhost:5000/echo');

ws.onmessage = function (evt) {
    console.log(JSON.parse(evt.data));
}

for (var i = 0; i < 10; i++) {
    var msg = {
        messageid: i,
        payload: 'An echo message.'
    };
    ws.send(JSON.stringify(msg));
}

正如预期的那样,所有客户端大致同时完成。但是,每个客户端收到的消息都按照它们发送的确切顺序 (messageid) 记录,就好像 WebSocketHandler 正在排队消息一样。 Python 服务器端的日志也反映了这一点。

那么,我的问题是:

请注意,这不是真实代码,而是合理的复制品。

您绝不能在 IOLoop 线程上 运行 "long, blocking calls",因为那样会阻塞其他一切。 sleep 调用(或它代表的任何内容)必须被重写为异步的或移交给另一个线程(这对于 concurrent.futures.ThreadPoolExecutor 来说相当容易)。有关详细信息,请参阅 http://www.tornadoweb.org/en/stable/faq.html#why-isn-t-this-example-with-time-sleep-running-in-parallel