为何按下Ctrl+C触发KeyboardInterrupt无法按预期终止进程?
为什么Ctrl+C无法中断你的进程?
核心原因
你的代码存在两个关键问题,导致KeyboardInterrupt无法按预期终止进程:
- ThreadPoolExecutor上下文管理器的阻塞等待:使用
with ThreadPoolExecutor时,退出with块会自动执行executor.shutdown(wait=True),这个方法会等待所有已提交的工作线程完成任务才会返回。而你的sleeper函数是无限循环,永远不会结束,进程因此卡在等待线程终止的步骤。 - 中断处理被上下文管理器覆盖:即使你捕获了KeyboardInterrupt并调用
exit(),with块的退出逻辑会优先执行——它会先等待所有工作线程完成,而这些线程无限运行,导致exit()根本无法生效。
解决方法
要让Ctrl+C正常终止进程,需要:
- 捕获中断时主动让线程池停止等待,同时将工作线程设为守护线程(主线程退出时,守护线程会被强制终止,不会阻塞主线程)。
修改后的代码示例:
from concurrent.futures import ThreadPoolExecutor import threading def sleeper(n): while True: pass def run(): # 创建线程池,自定义线程工厂生成守护线程 executor = ThreadPoolExecutor(max_workers=10) def daemon_thread_factory(): thread = threading.Thread() thread.daemon = True return thread executor._thread_factory = daemon_thread_factory try: results = executor.map(sleeper, list(range(120))) # 若需等待任务执行,可迭代results(示例中无此需求可省略) # for _ in results: # pass except KeyboardInterrupt: # 停止接受新任务,且不等待现有线程结束 executor.shutdown(wait=False) exit() finally: executor.shutdown(wait=False) if __name__ == '__main__': run()
补充说明
- 守护线程特性:主线程退出时,所有守护线程会被立即终止,不会阻塞主线程退出。
shutdown(wait=False):让线程池停止接受新任务,同时跳过对现有线程的等待,配合守护线程即可快速终止所有工作线程。
内容的提问来源于stack exchange,提问作者Vitaliy
相关产品推荐
相关产品推荐

