使用Tornado Web框架执行异步任务

时间:2017-08-27 12:32:51

标签: asynchronous concurrency event-handling tornado future

我熟悉事件驱动编程,但我遇到了这个问题,我已经终止了可能的解决方案。我阅读了Tornado的文档,我尝试过:

  1. 期货
  2. gen.coroutine
  3. 异步
  4. add_timeout
  5. 但我无法解决以下问题:

    • 我有一个只听新消息的websocket服务器 并根据消息类型调用特定函数

      class WebSocketHandler(tornado.websocket.WebSocketHandler):

      ...
      
      def on_message(self, message):
          if message['type'] is X:
              self.write(functionA(message['data']))
          elif message['type'] is Y:
              self.write(functionB(message['data']))
      ...
      

    当执行一个计算成本高的函数时出现问题,比如functionA,它可能需要5分钟才能终止

    def functionA(message):
        params = extract_params(message)
        cmd = "computationally_expensive_tool"
        out = check_output(cmd, shell=True, stderr=STDOUT, cwd=working_dir)
        ...
        return json.dumps({
                            "error": False,
                            "message": "computationally_expensive_tool_execution_terminated",
                            "type": X
                        })
    

    我的问题是如何以异步方式执行该功能,以便我可以在准备好后处理其他消息和functionA的结果?

1 个答案:

答案 0 :(得分:1)

如果functionA是一个无法异步的阻塞函数,您可能希望在线程池中运行它:

executor = concurrent.futures.ThreadPoolExecutor()

@gen.coroutine
def on_message(self, message):
    if message['type'] is X:
        yield executor.submit(functionA, message['data'])
    elif message['type'] is Y:
        functionB(message['data'])

这将阻止此websocket直到functionA完成,但允许其他连接继续工作。如果您需要在functionA运行时继续处理来自相同连接的其他类型的消息,则需要更复杂的安排,可能涉及tornado.queues.Queue