ThreadPoolExecutor 上 运行 游戏的龙卷风 4.x 解决方案不再有效。需要帮助重构它

Tornado 4.x solution of running game on ThreadPoolExecutor not working anymore. Need help refactoring it

我的 ThreadPoolExecutor/gen.coroutine(tornado v4.x) 绕过阻止网络服务器的解决方案不再适用于 tornado 版本 6.x.

不久前,我开始使用 Tornado 网络服务器 (v4.x) 和 websockets 开发在线浏览器游戏。每当需要用户输入时,游戏都会将问题发送给客户端并等待响应。比起我使用 gen.coroutine 和 ThreadPoolExecutor 来使这个任务成为非阻塞的。现在我开始重构游戏,它不能与 tornado v6.x 一起工作并且任务再次阻塞服务器。我搜索了可能的解决方案,但到目前为止我无法让它再次工作。我不清楚如何将现有代码再次更改为非阻塞。

server.py:

class PlayerWebSocket(tornado.websocket.WebSocketHandler):
    executor = ThreadPoolExecutor(max_workers=15)
    @run_on_executor
    def on_message(self,message):
        params = message.split(':')
        self.player.callbacks[int(params[0])]=params[1]

if __name__ == '__main__':
    application = Application()
    application.listen(9999)
    tornado.ioloop.IOLoop.instance().start()

player.py:

@gen.coroutine
def send(self, message):
   self.socket.write_message(message)

def create_choice(self, id, choices):
    d = {}
    d['id'] = id
    d['choices']=choices
    self.choice[d['id']]=d
    self.send('update',self)
    while not d['id'] in self.callbacks:
        pass
    del self.choice[d['id']]
    return self.callbacks[d['id']]

每当要做出选择时,create_choice 函数会创建一个带有列表(选择)和 id 的字典,并将其存储在玩家 self.callbacks 中。之后它一直停留在 while 循环中,直到 websocket.on_message 函数将收到的答案(看起来像这样:id:Choice_id,例如 1:12838732)放入回调字典中。

WebSocketHandler.write_message 方法不是线程安全的,因此它只能从 IOLoop 的线程中调用,而不能从 ThreadPoolExecutor 中调用(这一直是正确的,但有时它似乎无论如何都可以工作).

修复此代码的最简单方法是将 IOLoop.current() 保存在主线程的全局变量中(current() 函数访问线程局部变量,因此您不能从中调用它线程池)并使用 ioloop.add_callback(self.socket.write_message, message)(并从 send 中删除 @gen.coroutine - 如果它们不包含 yield 表达式,则使函数协程没有任何好处)。