tornado服务器与线程模块不兼容

时间:2016-09-08 02:07:08

标签: multithreading tornado

我正在使用带线程的龙卷风。

简而言之,每次websocket处理程序收到请求时,都会开始执行一项任务,这可能需要几分钟时间。

但是,一旦连接了客户端,就无法连接其他客户端,直到第一个客户端断开连接。

有什么想法吗?

我附上了一个使用time.sleep来模拟长时间运行任务的最小示例。

import tornado.web
import tornado.websocket
import tornado.httpserver
import tornado.ioloop
import time
import json
import threading

class TaskHandler(tornado.websocket.WebSocketHandler):
    def open(self):
        pass

    def check_origin(self, origin):
        return True

    def on_message(self, message):
        try:
            print 'received: ', message
            self.write_message(json.dumps({'status': 'running'}))

            def worker_A(kwargs):
                time.sleep(100)
                pass

            def worker_B(kwargs):
                time.sleep(100)
                pass

            threads = []
            for target in [worker_A, worker_B]:
                t = threading.Thread(target = target, args = ({'xxx': 'yyy'}, ))
                t.daemon = True
                t.start()
                threads.append(t)

            for t in threads:
                t.join()

        except Exception, e:
            print 'TaskHandler: exception: ', e
            pass

        self.write_message(json.dumps({'status': 'done'}))

    def on_close(self):
        pass

class Server(tornado.web.Application):
    def __init__(self):
        handlers = [
            ('/task', TaskHandler),
        ]

        tornado.web.Application.__init__(self, handlers)

if __name__ == '__main__':
    server  = tornado.httpserver.HTTPServer(Server())
    server.listen(8765, address = '127.0.0.1')
    tornado.ioloop.IOLoop.instance().start()

1 个答案:

答案 0 :(得分:1)

您在t.join中阻止整个Tornado事件循环100秒。除非您有yield语句或安排回调并退出函数,否则您的函数不是异步的。注意你的函数“on_message”是如何开始两个线程然后在每个线程上调用t.join的 - 当你的函数等待t.join时,Tornado的事件循环如何完成任何其他工作?

相反,请使用类似这样的ThreadPoolExecutor:

thread_pool = ThreadPoolExecutor(4)

class TaskHandler(tornado.websocket.WebSocketHandler):
    # Make this an asynchronous coroutine
    @gen.coroutine
    def on_message_coroutine(self, message):
        print 'received: ', message
        self.write_message(json.dumps({'status': 'running'}))

        def worker_A(kwargs):
            time.sleep(100)
            pass

        def worker_B(kwargs):
            time.sleep(100)
            pass

        futures = []
        for target in [worker_A, worker_B]:
            f = thread_pool.submit(target, {'xxx': 'yyy'})
            futures.append(future)

        # Now the event loop can do other things
        yield futures

    def on_message(self, message):
        IOLoop.current().spawn_callback(self.on_message_coroutine,
                                        message)