You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何按下Ctrl+C触发KeyboardInterrupt无法按预期终止进程?

为什么Ctrl+C无法中断你的进程?

核心原因

你的代码存在两个关键问题,导致KeyboardInterrupt无法按预期终止进程:

  1. ThreadPoolExecutor上下文管理器的阻塞等待:使用with ThreadPoolExecutor时,退出with块会自动执行executor.shutdown(wait=True),这个方法会等待所有已提交的工作线程完成任务才会返回。而你的sleeper函数是无限循环,永远不会结束,进程因此卡在等待线程终止的步骤。
  2. 中断处理被上下文管理器覆盖:即使你捕获了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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 01:47:10