我已经在这篇文章中读到,使用ThreadingMixin
(来自SocketServer
模块),您可以使用BaseHTTPServer
. 我已经尝试过了,它确实有效。但是,如何停止服务器产生的活动线程(例如,在服务器关闭期间)?这可能吗?
2 回答
最简单的解决方案是只使用daemon_threads
. 简短的版本是:只需将其设置为 True,不用担心;当您退出时,任何仍在工作的线程都会自动停止。
正如ThreadingMixIn
文档所说:
当从 ThreadingMixIn 继承线程连接行为时,您应该明确声明您希望线程在突然关闭时的行为方式。ThreadingMixIn 类定义了一个属性 daemon_threads,它指示服务器是否应该等待线程终止。如果您希望线程自主运行,则应显式设置该标志;默认值为 False,这意味着 Python 在 ThreadingMixIn 创建的所有线程都退出之前不会退出。
threading
文档中提供了更多详细信息:
可以将线程标记为“守护线程”。这个标志的意义在于,当只剩下守护线程时,整个 Python 程序就退出了。初始值继承自创建线程。可以通过 daemon 属性设置标志。
有时这是不合适的,因为您想在不退出的情况下关闭,或者因为您的处理程序可能需要进行清理。但在适当的时候,你不能变得更简单。
如果您只需要一种在不退出的情况下关闭的方法,并且不需要保证清理,您可以通过ctypes
或使用特定于平台的线程取消 API win32api
。这通常是一个坏主意,但有时这正是您想要的。
如果您需要彻底关闭,则需要为此构建自己的机器,线程协作的地方。例如,您可以创建一个由 a 保护的全局“退出标志”变量threading.Condition
,并让您的handle
函数定期检查它。
如果线程只是在做缓慢的、非阻塞的工作,你可以把它分解成更小的部分,那就太好了。例如,如果该handle
函数始终至少每 5 秒检查一次退出标志,则可以保证能够在 5 秒内关闭线程。但是如果线程正在做阻塞工作——因为它们可能是这样,因为你使用的全部原因ThreadingMixIn
是让你进行阻塞调用而不是编写select
循环或使用asyncore
等?
好吧,没有好的答案。显然,如果您只需要“最终”而不是“在 5 秒内”发生关闭(或者如果您愿意在 5 秒后放弃干净关闭,并恢复使用特定于平台的 API 或守护线程),您只需在每次阻塞调用之前和之后进行检查,它就会“经常”工作。但如果这还不够好,你真的无能为力。
如果你需要这个,最好的答案是改变你的架构以使用有办法做到这一点的框架。最受欢迎的选择是Twisted
、Tornado
和gevent
。将来,PEP 3156会将类似的功能引入标准库,tulip
如果您不想为现实世界构建一些必须尽快准备好的东西,那么有一个部分完整的参考实现值得一玩。
下面的示例代码展示了如何使用 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()
服务器已完全关闭,因此您可以立即重新启动服务器并且端口可用,而不是获得“地址已在使用中”。