windows下python threading.Event wait时自定义的信号处理无法触发
问题来源
用uvicorn跑fastapi的时候发现ctrl+c关闭程序怪怪的,开多进程的时候,表现为按下停止后pycharm停止按钮变成骷髅,只能再点一次强制关闭
看了一下源码,基本问题定位在 https://github.com/encode/uvicorn/blob/master/uvicorn/supervisors/multiprocess.py
def signal_handler(self, sig: int, frame: Optional[FrameType]) -> None:
"""
A signal handler that is registered with the parent process.
"""
self.should_exit.set()
def run(self) -> None:
self.startup()
self.should_exit.wait()
self.shutdown()
看上去是因为sigint没有触发signal_handler
早有耳闻python在win和linux的信号处理有差异,就马上在linux试了一下,发现一切正常。
uvicorn实际问题比较复杂,放一个简单场景
import signal
import threading
import win32api
event = threading.Event()
def signal_handler(sig, frm):
print("ctrl+c")
event.set()
def ctrl_handler(*args, **kwargs):
"""
ChatGPT说
在 ctrl_handler(ctrl_type) 函数中,ctrl_type 参数表示控制台收到的信号类型。在 Windows 平台上,ctrl_type 可以有以下几个值:
0:表示收到了 CTRL_C_EVENT 中断信号,通常是用户按下了 Ctrl+C。
1:表示收到了 CTRL_BREAK_EVENT 中断信号,通常是用户按下了 Ctrl+Break。
2:表示收到了 CTRL_CLOSE_EVENT 中断信号,通常是用户关闭了控制台窗口。
3:表示收到了 CTRL_LOGOFF_EVENT 中断信号,通常是用户注销了系统。
4:表示收到了 CTRL_SHUTDOWN_EVENT 中断信号,通常是用户关闭了系统。
在 ctrl_handler 函数中,我们可以根据 ctrl_type 的值来判断收到的是哪种中断信号,然后进行相应的处理。通常情况下,我们只需要处理 0 和 1 两种中断信号,因为它们是由用户按下 Ctrl+C 和 Ctrl+Break 触发的,是用户主动要求中断程序的。
:param kwargs:
:return:
"""
print(args, kwargs) # (0,) {}
event.set()
return True
class JB:
def stop(self):
print("job", id(self), "stop")
def main():
# signal.signal(signal.SIGINT, signal_handler)
win32api.SetConsoleCtrlHandler(ctrl_handler, True)
jbs = [JB(), JB()]
print(len(jbs), "jobs is running")
event.wait()
for jb in jbs:
jb.stop()
print('Event triggered!')
if __name__ == '__main__':
main()
把signal换成了win下特定的win32api.SetConsoleCtrlHandler,就可以在wait的时候处理ctrl+c了
ps:感觉这是uvicorn的一个小bug,什么时候想个更好的办法,可以给uvicorn提个pr 嘿嘿
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)