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

Python multiprocessing在Windows下遇KeyboardInterrupt无法终止致系统冻结

解决Windows下Python多进程Pool按Ctrl+C锁死的问题

首先,你的代码里有几个关键问题会导致这个锁死现象,再加上Windows系统对多进程信号处理的特殊性,才触发了机器锁死的情况。我来一步步拆解和修复:

1. 先修正代码里的明显错误

你把pool.close()放在了os.walk的循环内部,这意味着第一次遍历完一个目录后,进程池就被关闭了,后续的目录处理会直接报错,而且pool.join()的位置也不对,这会导致资源无法正确释放,是锁死的诱因之一。另外,pool.map()返回的是计算完成的结果列表,不是AsyncResult对象,所以item.wait()完全是无效操作——你等的根本不是异步任务句柄。

2. Windows下Ctrl+C导致锁死的核心原因

在Windows系统中,Python的multiprocessing.Pool的map()方法是完全阻塞的,主进程会一直等待所有子进程完成任务。当你按下Ctrl+C时,主进程收到KeyboardInterrupt,但子进程可能还在执行IO密集型的哈希计算(比如读取大文件),Windows的信号机制无法像Unix那样快速传递终止信号给子进程,导致子进程继续占用CPU和内存资源,甚至和主进程产生资源竞争,最终引发系统锁死。

3. 修复后的代码方案

我们可以改用pool.imap()(或者imap_unordered())来迭代处理结果,这样主进程不会一直阻塞,而是能及时响应中断信号;同时正确管理进程池的生命周期,不在循环内关闭池:

import os
import multiprocessing

def is_valid_file(file_path):
    # 你的文件校验逻辑
    return os.path.isfile(file_path)

def getHashes(file_path):
    # 你的哈希计算逻辑
    import hashlib
    with open(file_path, 'rb') as f:
        return hashlib.sha256(f.read()).hexdigest()

def syncHashes(rootDir):
    """ main function """
    print(f"Starting the scanner in root {rootDir}")
    pool = multiprocessing.Pool(processes=10)
    try:
        for dirName, subdirList, fileList in os.walk(rootDir):
            full_path_fnames = map(lambda fn: os.path.join(dirName, fn), fileList)
            full_path_fnames = filter(is_valid_file, full_path_fnames)
            # 使用imap迭代处理,让主进程能响应中断
            for result in pool.imap(getHashes, full_path_fnames):
                # 处理每个文件的哈希结果
                print(f"Hash: {result}")
        # 遍历完成后再关闭池
        pool.close()
        pool.join()
    except KeyboardInterrupt:
        print("Received interrupt, terminating pool...")
        pool.terminate()
        pool.join()

if __name__ == "__main__":
    syncHashes(".")  # 替换成你的rootDir

4. 额外优化建议

  • 如果你的哈希计算是IO密集型的(读取大量文件),可以考虑减少进程数(比如和CPU核心数一致),避免磁盘IO竞争加剧锁死概率。
  • 也可以尝试使用concurrent.futures.ProcessPoolExecutor,它的中断处理在Windows下更健壮:
from concurrent.futures import ProcessPoolExecutor

def syncHashes(rootDir):
    print(f"Starting the scanner in root {rootDir}")
    with ProcessPoolExecutor(max_workers=10) as executor:
        try:
            for dirName, subdirList, fileList in os.walk(rootDir):
                full_path_fnames = map(lambda fn: os.path.join(dirName, fn), fileList)
                full_path_fnames = filter(is_valid_file, full_path_fnames)
                for result in executor.map(getHashes, full_path_fnames):
                    print(f"Hash: {result}")
        except KeyboardInterrupt:
            print("Received interrupt, shutting down executor...")
            executor.shutdown(wait=False)

这个方案利用了with语句自动管理执行器的生命周期,shutdown(wait=False)会立即终止所有子进程,避免资源占用。

内容的提问来源于stack exchange,提问作者ensnare

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:38:57