【发布时间】:2013-01-11 19:02:50
【问题描述】:
我在this post 上读到过,使用ThreadingMixin(来自SocketServer 模块),您可以使用BaseHTTPServer 创建线程服务器。我已经尝试过了,它确实有效。但是,如何停止服务器产生的活动线程(例如,在服务器关闭期间)?这可能吗?
【问题讨论】:
标签: python multithreading python-2.7 basehttpserver
我在this post 上读到过,使用ThreadingMixin(来自SocketServer 模块),您可以使用BaseHTTPServer 创建线程服务器。我已经尝试过了,它确实有效。但是,如何停止服务器产生的活动线程(例如,在服务器关闭期间)?这可能吗?
【问题讨论】:
标签: python multithreading python-2.7 basehttpserver
最简单的解决方案是使用daemon_threads。简短的版本是:只需将其设置为 True,不用担心;当您退出时,任何仍在工作的线程都会自动停止。
正如ThreadingMixIn docs 所说:
当从 ThreadingMixIn 继承线程连接行为时,您应该明确声明您希望线程在突然关闭时的行为方式。 ThreadingMixIn 类定义了一个属性 daemon_threads,它指示服务器是否应该等待线程终止。如果您希望线程自主运行,则应显式设置该标志;默认为 False,表示 Python 在 ThreadingMixIn 创建的所有线程都退出之前不会退出。
更多详情请见threading docs:
可以将线程标记为“守护线程”。这个标志的意义在于,当只剩下守护线程时,整个 Python 程序就退出了。初始值继承自创建线程。该标志可以通过 daemon 属性设置。
有时这是不合适的,因为您想在不退出的情况下关闭,或者因为您的处理程序可能需要进行清理。但是当它是合适的时候,你再简单不过了。
如果您只需要一种在不退出的情况下关闭的方法,并且不需要保证清理,您可以通过ctypes 或win32api 使用特定于平台的线程取消API。这通常是个坏主意,但有时这正是您想要的。
如果您需要彻底关闭,则需要为此构建自己的机器,让线程相互协作。例如,您可以创建一个受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()
服务器已完全关闭,因此您可以立即重新启动服务器并且端口可用,而不是获取“地址已在使用中”。
【讨论】: