将锁传递给ProcessPoolExecutor工作进程导致不运行问题求助
问题根因
executor.submit传参语法错误:你把path和lock两个参数放在了同一个括号里,相当于给addToImageVector只传了1个元组类型的参数,和函数定义的两个入参不匹配,子进程启动后直接触发参数数量不匹配的异常,自然不会执行到print('hi guy')的逻辑。- 进程间共享锁的初始化和传递逻辑错误:你在
for action的循环内才创建multiprocessing.Lock,且直接作为参数提交给进程池任务,在使用spawn模式创建进程的平台(比如Windows)下,这种传递方式会导致锁无法正常序列化/共享,进一步引发子进程运行异常。
修复方案
第一步 修正submit传参语法
把原来的错误写法:
executor.submit(addToImageVector, (normpath(VID_PATH + action + file), lock))
改为去掉多余括号,参数分开传递:
executor.submit(addToImageVector, normpath(VID_PATH + action + file), lock)
第二步 调整共享锁的初始化逻辑
锁需要在进程池初始化阶段就设置为全局可共享的变量,不要在循环内创建,也不要直接作为任务参数传递,参考实现如下:
import multiprocessing as m from concurrent.futures import ProcessPoolExecutor import os import json from os.path import normpath # 全局变量用于保存共享锁 _process_lock = None def init_pool(lock): """进程池初始化回调,给每个子进程设置共享锁""" global _process_lock _process_lock = lock def addToImageVector(path: str): # 直接用全局的共享锁,不需要作为参数传入 print('hi guy', flush=True) data: dict = None with _process_lock: with open('path\\amounts.json', 'r') as f: data = json.load(fp=f) # 剩余原有业务逻辑 ... if __name__ == "__main__": # 替换为你自己的原有配置 ACTIONS = ["boost", "click", "upgrade"] VID_PATH = "你的视频根目录路径" NUMBER_OF_CPUS = os.cpu_count() USE_UP_TO = 0.5 max_workers = int(NUMBER_OF_CPUS * USE_UP_TO) # 锁在主进程提前创建 lock = m.Lock() # 初始化进程池的时候传入锁的初始化函数和锁对象 with ProcessPoolExecutor(max_workers=max_workers, initializer=init_pool, initargs=(lock,)) as executor: for action in ACTIONS: for file in os.listdir(normpath(VID_PATH + action)): file_path = normpath(VID_PATH + action + file) print(file_path) # 只需要传path参数,锁已经是子进程全局共享的了 executor.submit(addToImageVector, file_path)
额外注意点
- 子进程的print内容默认带缓冲区,如果还是看不到打印,给print加
flush=True参数即可强制刷新输出。 - 操作JSON文件时,读写逻辑都要放在锁的上下文里,避免读写冲突导致文件损坏。
内容的提问来源于stack exchange,提问作者romhayh
相关产品推荐
相关产品推荐

