我的ThreadPoolExecutor / gen.coroutine(tornado v4.x)解决方案,用于阻止Web服务器,在龙卷风6.x版中不再起作用。
前一段时间,我开始使用Tornado网络服务器(v4.x)和websocket开发在线浏览器游戏。每当需要用户输入时,游戏就会将问题发送给客户端并等待响应。早于我使用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)放入回调dict中。
答案 0 :(得分:0)
WebSocketHandler.write_message
方法不是线程安全的,因此只能从IOLoop的线程中调用,而不能从ThreadPoolExecutor中调用(这一直是对的,但有时似乎仍然可以工作)。
修复此代码的最简单方法是将IOLoop.current()
保存在主线程的全局变量中(current()
函数访问线程局部变量,因此您无法从线程中调用它池)并使用ioloop.add_callback(self.socket.write_message, message)
(并从@gen.coroutine
中删除send
-如果不包含函数yield
,则使协程成为无效)。