使用multiprocessing的starmap运行测试函数,找到指定排列时如何安全终止所有进程?
在multiprocessing中找到目标排列时终止所有进程的最佳方案
你的问题核心在于starmap是阻塞式的——它会一直等待所有子进程完成任务才会返回,没办法中途终止。要实现“找到目标就立刻停掉所有进程”,我们需要改用异步任务提交+跨进程共享的终止信号,下面是最安全可靠的实现方式:
核心思路
- 使用
multiprocessing.Manager().Event()创建一个跨进程共享的事件对象,所有子进程都能监听这个事件的状态。 - 用
apply_async异步提交任务(替代starmap),这样主进程可以实时监控事件状态,不用等到所有任务结束。 - 每个子进程在循环中定期检查事件:如果事件被触发(即找到目标),就立即退出循环;一旦找到目标排列,就设置这个事件通知所有进程。
- 主进程检测到事件触发后,调用
pool.terminate()立即终止所有子进程,避免不必要的计算。
完整代码实现
import multiprocessing as mp import random import time def testing(stop_event): start_time = time.time() # 给每个子进程单独初始化随机种子,避免多个进程生成重复的随机序列 random.seed() # 循环执行直到收到终止信号 while not stop_event.is_set(): gg = [1, 2, 3, 4, 5] random.shuffle(gg) if gg == [5, 2, 4, 3, 1]: print(f"🎉 找到目标排列!耗时: {time.time() - start_time:.2f}秒") # 设置终止事件,通知所有进程停止 stop_event.set() break total_time = time.time() - start_time return total_time if __name__ == '__main__': # 使用Manager创建跨进程共享的事件 with mp.Manager() as manager: stop_event = manager.Event() with mp.Pool(processes=4) as pool: # 异步提交4个测试任务 async_tasks = [pool.apply_async(testing, args=(stop_event,)) for _ in range(4)] # 主进程轮询事件状态,直到事件被触发 while not stop_event.is_set(): time.sleep(0.1) # 降低轮询频率,减少CPU占用 # 立即终止所有子进程(比close()更直接,close()会等待任务完成) pool.terminate() pool.join() # 可选:收集已完成的进程结果 print("\n各进程执行情况:") for idx, task in enumerate(async_tasks, 1): try: duration = task.get(timeout=1) print(f"进程{idx}:耗时 {duration:.2f}秒") except mp.TimeoutError: print(f"进程{idx}:未完成即被终止")
关键细节说明
- 为什么不用
starmap?:starmap是批量提交任务且阻塞的,主进程会卡在pool.starmap()这一行直到所有任务结束,根本没机会中途终止进程。异步的apply_async才是正确的选择。 - 共享事件的安全性:
Manager.Event()是线程/进程安全的,多个进程同时读写不会出现竞态条件。 pool.terminate()vspool.close():close()会等待所有已提交的任务完成后再关闭池,而我们需要的是立即终止所有进程,所以用terminate()更合适。- 随机种子初始化:如果不给每个子进程单独设置随机种子,多个子进程可能会生成相同的随机序列(因为默认会继承主进程的种子),这样会浪费计算资源。
内容的提问来源于stack exchange,提问作者Panos Kalatzantonakis
相关产品推荐
相关产品推荐

