【问题标题】:Tornado multiple IOLoop in multithreadsTornado 多线程中的多个 IOLoop
【发布时间】:2016-07-28 19:16:13
【问题描述】:

我试图在多个线程中运行多个 IOLoop,我想知道 IOLoop 是如何工作的。

class WebThread(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self, name='WebThread')

    def run(self):
        curdir = os.path.dirname(os.path.realpath(__file__))

        application = Application() #Very simple tornado.web.Application
        http_server_api = tornado.httpserver.HTTPServer(application)
        http_server_api.listen(8888)

        logging.info('Starting application')

        #tornado.ioloop.IOLoop.instance() is singleton, not for thread, right?

        ioloop = tornado.ioloop.IOLoop()
        ioloop.make_current()
        ioloop.start()

根据文档,我不能使用 IOLoop.instance() 因为它是一个单例并且我正在一个线程中工作。所以我创建了自己的 IOLoop。但是这段代码监听了 8888 端口,却无法渲染任何网页。我想知道是否遗漏了什么,或者我是否需要以某种方式将 http_server 绑定到 IOLoop?

另外,我发现删除最后 3 行并替换为 tornado.ioloop.IOLoop.instance().start 非常适合单线程。但是单例和自创的 IOLoop 有什么区别呢?

我是 Tornado 的新手,欢迎任何答案。

【问题讨论】:

    标签: python multithreading tornado


    【解决方案1】:

    一般来说,在构造异步对象时应使用 IOLoop.current 作为默认值,而当您打算从不同的主线程与主线程通信时,应使用 IOLoop.instance。

    IOLoop.current 不带参数返回已经创建线程的ioloop 或者它调用IOLoop.instance()。而 HTTPServer(实际上在 TCPServer 中)使用 IOLoop.current 与 ioloop 进行交互,因此您唯一应该更改的是在 HTTPServer 之前创建 ioloop,例如

    class WebThread(threading.Thread):
        def __init__(self):
            threading.Thread.__init__(self, name='WebThread')
    
        def run(self):
            curdir = os.path.dirname(os.path.realpath(__file__))
    
            ioloop = tornado.ioloop.IOLoop()
    
            application = Application() #Very simple tornado.web.Application
            http_server_api = tornado.httpserver.HTTPServer(application)
            http_server_api.listen(8888)
    
            logging.info('Starting application')
    
            ioloop.start()
    

    我还删除了 IOLoop.make_current,因为它是多余的 - IOLoop() 将 self 设置为当前。


    上面的代码可以工作,但只有一个线程,因为reuse_port默认没有启用。你最终会得到:

    OSError: [Errno 98] Address already in use
    

    您可以使用

    启用此功能
        http_server_api.bind(port=8888, reuse_port=True)
        http_server_api.start()
    

    而不是http_server_api.listen(8888)

    【讨论】:

    • 这是一个很棒的答案,谢谢。我不知道 http_server 正在与当前的 IOLoop 交互。非常感谢您的解释。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-01
    • 1970-01-01
    • 2016-11-17
    • 2018-09-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多