【问题标题】:Stopping threads spawned by BaseHTTPServer using ThreadingMixin使用 ThreadingMixin 停止 BaseHTTPServer 产生的线程
【发布时间】:2013-01-11 19:02:50
【问题描述】:

我在this post 上读到过,使用ThreadingMixin(来自SocketServer 模块),您可以使用BaseHTTPServer 创建线程服务器。我已经尝试过了,它确实有效。但是,如何停止服务器产生的活动线程(例如,在服务器关闭期间)?这可能吗?

【问题讨论】:

    标签: python multithreading python-2.7 basehttpserver


    【解决方案1】:

    最简单的解决方案是使用daemon_threads。简短的版本是:只需将其设置为 True,不用担心;当您退出时,任何仍在工作的线程都会自动停止。

    正如ThreadingMixIn docs 所说:

    当从 ThreadingMixIn 继承线程连接行为时,您应该明确声明您希望线程在突然关闭时的行为方式。 ThreadingMixIn 类定义了一个属性 daemon_threads,它指示服务器是否应该等待线程终止。如果您希望线程自主运行,则应显式设置该标志;默认为 False,表示 Python 在 ThreadingMixIn 创建的所有线程都退出之前不会退出。

    更多详情请见threading docs

    可以将线程标记为“守护线程”。这个标志的意义在于,当只剩下守护线程时,整个 Python 程序就退出了。初始值继承自创建线程。该标志可以通过 daemon 属性设置。

    有时这是不合适的,因为您想在不退出的情况下关闭,或者因为您的处理程序可能需要进行清理。但是当它合适的时候,你再简单不过了。

    如果您只需要一种在不退出的情况下关闭的方法,并且不需要保证清理,您可以通过ctypeswin32api 使用特定于平台的线程取消API。这通常是个坏主意,但有时这正是您想要的。

    如果您需要彻底关闭,则需要为此构建自己的机器,让线程相互协作。例如,您可以创建一个受threading.Condition 保护的全局“退出标志”变量,并让您的handle 函数定期检查它。

    如果线程只是在做缓慢的、非阻塞的工作,你可以把它分解成更小的部分,那就太好了。例如,如果handle 函数始终至少每 5 秒检查一次退出标志,则可以保证能够在 5 秒内关闭线程。但是如果线程正在做阻塞工作——因为它们可能是,因为你使用ThreadingMixIn 的全部原因是让你进行阻塞调用而不是编写select 循环或使用asyncore 或类似的东西?

    嗯,没有好的答案。显然,如果您只需要“最终”而不是“在 5 秒内”发生关闭(或者如果您愿意在 5 秒后放弃干净关闭,并恢复使用特定于平台的 API 或守护线程),您可以在每次阻塞调用之前和之后进行检查,它会“经常”工作。但如果这还不够好,你真的无能为力。

    如果您需要这个,最好的答案是改变您的架构以使用有办法做到这一点的框架。最受欢迎的选择是TwistedTornadogevent。将来,PEP 3156 将把类似的功能带入标准库,如果你不想为现实世界构建一些必须很快准备好的东西,还有一个部分完整的参考实现tulip 值得一玩.

    【讨论】:

      【解决方案2】:

      这里的示例代码展示了如何使用 threading.Event 在任何 POST 请求上关闭服务器,

      import SocketServer
      import BaseHTTPServer
      import threading
      
      quit_event = threading.Event()
      
      class MyRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
        """This handler fires the quit event on POST."""
        def do_GET(self):
          self.send_response(200)
        def do_POST(self):
          quit_event.set()
          self.send_response(200)
      
      
      class MyThreadingHTTPServer(
          SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer):
        pass
      
      server = MyThreadingHTTPServer(('', 8080), MyRequestHandler)
      threading.Thread(target=server.serve_forever).start()
      quit_event.wait()
      server.shutdown()
      

      服务器已完全关闭,因此您可以立即重新启动服务器并且端口可用,而不是获取“地址已在使用中”。

      【讨论】:

        猜你喜欢
        • 2012-02-06
        • 2018-06-23
        • 1970-01-01
        • 1970-01-01
        • 2012-07-14
        • 2014-02-11
        • 2020-01-28
        • 2015-06-23
        • 2018-09-02
        相关资源
        最近更新 更多