【问题标题】:Tornado web server ioloop error on .stop().stop() 上的 Tornado Web 服务器 ioloop 错误
【发布时间】:2015-12-05 12:00:02
【问题描述】:

我在 Tornado 上构建了 Web 服务器。以下是主要 WebServer 类的一些部分:

import tornado.ioloop as tio
...

class WebServer(object):

    def __init__(.....):
        ...
        self.IOloop = tio.IOLoop.instance()
        ...

    def __call__(self):
        self.logger('info', 'Web server', 'Starting web server on port %s, waiting for connection...' % (self.port))
        if self.verbose:
            print 'Starting web server on port %s, waiting for connection...' % (self.port)
        try:
            self.application.listen(self.port)
            self.IOloop.start()
        except Exception as error:
            self.logger('error', 'Web server', str(error), exc_info = True)
        self.stop()
        if self.verbose:
            print 'Web server shut down'
        self.logger('info', 'Web server', 'Stopped')

    def stop(self):
        if self.up:
            self.logger('info', 'Web server', 'Shutting down...')
            ioloop = tio.IOLoop.current()
            ioloop.stop()
            ioloop.close()
            self.ws_controller.stop()
            self.ws_thread.join()
            self.up = False

服务器实例是运行的众多不同后端对象之一。我在单独的线程中启动服务器实例以及其他后端对象:

def assign_component(self, name, config_name, class_):
    self.components[name] = class_(bus = self.bus, logger = self.logger, config = self.config[config_name], verbose = self.verbose)
    setattr(self, name, self.components[name])
    self.threads[name] = thr.Thread(target = self.components[name])
    self.threads[name].start()

在这种情况下,class_ 是 WebServer。 它的工作没有问题。但是当我想停止整个应用程序时,我遇到了以下错误:

ERROR:tornado.application:Exception in callback None
  Traceback (most recent call last):
    File "/root/anaconda2/lib/python2.7/site-packages/tornado/ioloop.py", line 865, in start
      fd_obj, handler_func = self._handlers[fd]
KeyError: 29

我阅读了很多文章,它们讲述了关于线程不安全和 add_callback 的一些内容,但我不明白如果我只想启动和停止 IOloop 的主实例,为什么还需要一些回调?我对龙卷风 IOloop 的理解缺少什么?

【问题讨论】:

  • 后台线程是否与 IOLoop 或 Tornado 的任何其他部分有任何交互?后台线程如何与实际的 Web 服务器通信?
  • 所有后台线程都通过特殊的对象-总线进行通信,通过信号/事件和请求,每个对象都有相同的总线实例。我不确定与 IOLoop 交互是什么意思,因为我只启动它并且它挂起,为 Web 服务器提供服务。当我想从主线程停止 IOLoop 时会发生此错误。

标签: python webserver tornado python-multithreading


【解决方案1】:

IOLoop 中唯一的线程安全方法是add_callback。您可以使用它来停止 IOLoop。但是,未经测试,它将类似于:

...
def stop(self):
    if self.up:
        self.logger('info', 'Web server', 'Shutting down...')
        self.IOLoop.add_callback(lambda x: x.stop(), self.IOLoop)
        self.ws_controller.stop()
        self.ws_thread.join()
        self.up = False

一些相关问题:How do I stop Tornado web server?

附:提供minimum working example是个好习惯。

【讨论】:

  • 另外,__call__不应该调用IOLoop.stop(start()返回后,循环已经停止),对IOLoop.close的调用应该在__call__中,而不是WebServer.stop。请参阅tornadoweb.org/en/stable/…中的注释
  • 效果很好,谢谢!抱歉没有提供最小的工作示例(我的代码很大,无法放在这里),下次会注意这个并准备一些简单的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多