Python中如何从主线程停止运行Web服务器的子线程?
优雅停止子线程中的Web服务器
不需要通过kill整个进程终止Web服务器,也不用模拟KeyboardInterrupt信号。Python的http.server.HTTPServer本身提供了shutdown()方法,能优雅终止serve_forever()循环,让子线程自然退出。
修改方案
核心是让主线程能访问到子线程中的httpd实例,调用其shutdown()方法完成优雅关闭:
- 将子线程中的
httpd实例保存为全局变量,供主线程调用 - 在
tearDownClass中先触发服务器关闭,再等待子线程完全退出
修改后的完整代码
import http import os import sys import unittest import time import requests import threading from addresses import handle_get_addresses, load_addresses from webserver import HTTPHandler # 全局变量保存httpd实例,让主线程可访问 httpd_instance = None def run_in_thread(fn): def run(*k, **kw): t = threading.Thread(target=fn, args=k, kwargs=kw) t.start() return t return run @run_in_thread def start_web_server(): global httpd_instance web_host = 'localhost' print("starting server...") web_port = 8808 httpd_instance = http.server.HTTPServer((web_host, web_port), HTTPHandler) try: httpd_instance.serve_forever() finally: # 确保服务器套接字被关闭,避免端口占用 httpd_instance.server_close() class TestAddressesApi(unittest.TestCase): WEB_SERVER_THREAD: threading.Thread = None @classmethod def setUpClass(cls): cls.WEB_SERVER_THREAD = start_web_server() # 短暂等待服务器启动完成,避免测试请求连接失败 time.sleep(0.5) @classmethod def tearDownClass(cls): print("shutting down the webserver...") # 优雅停止服务器 if httpd_instance: httpd_instance.shutdown() # 等待子线程完全退出 cls.WEB_SERVER_THREAD.join() def test_get_all_addresses(self): # 示例测试逻辑 response = requests.get("http://localhost:8808/addresses") self.assertEqual(response.status_code, 200) def test_1(self): # 其他测试逻辑 pass if __name__ == "__main__": unittest.main()
关键说明
httpd.shutdown()会通知serve_forever()循环正常退出,不会强制中断正在处理的请求,属于优雅关闭thread.join()确保子线程完全结束后,主线程再继续执行后续流程- 添加
time.sleep(0.5)是为了避免测试在服务器未完全启动时发起请求,导致连接失败 finally块保证无论服务器如何退出,套接字都会被正确关闭,避免端口被占用
内容的提问来源于stack exchange,提问作者Timofey Borisov
相关产品推荐
相关产品推荐

