Python通过信号量控制多进程并发

📅 2026/7/23 2:31:34
Python通过信号量控制多进程并发
在 Python 的multiprocessing模块中信号量Semaphore是一种强大的同步原语用于控制对共享资源的并发访问数量。它与互斥锁Lock不同互斥锁一次只允许一个进程访问而信号量可以允许指定数量的进程同时访问。你可以把信号量想象成一个有固定数量钥匙的柜子一个进程要执行任务必须先acquire()取走一把钥匙任务完成后必须release()归还钥匙。当所有钥匙都被取走时其他进程就必须等待。这个“钥匙”的数量就是信号量允许的最大并发数。核心APISemaphore(value1): 创建一个信号量对象。value是初始化时“钥匙”的数量即允许的最大并发进程数。acquire(blockingTrue, timeoutNone): 请求一把“钥匙”。若计数器 0则计数器减1进程继续执行。若计数器 0进程会阻塞直到有可用的“钥匙”。release(): 归还一把“钥匙”计数器加1。上下文管理器: 推荐使用with semaphore:语句它会自动调用acquire()和release()能有效避免因异常导致锁未释放的问题。关键注意事项在多进程编程中信号量的创建位置至关重要。正确做法必须在主进程中创建信号量然后作为参数传递给子进程。错误做法将信号量创建为全局变量。在 Windows 或 macOS使用spawn方式创建进程上每个子进程会重新导入模块创建出各自的信号量副本导致同步失效。完整示例模拟限流打印任务下面这个例子模拟了一个最多允许3个进程同时执行任务的场景。importmultiprocessingimporttimeimportrandomdefworker(process_id,semaphore): 模拟一个工作进程。 在进入临界区前必须获取信号量。 # 使用 with 语句管理信号量更安全withsemaphore:# 进入临界区start_timetime.strftime(%H:%M:%S)print(f[{start_time}] 进程{process_id}开始执行任务...)# 模拟一个耗时任务耗时 1~3 秒work_durationrandom.randint(1,3)time.sleep(work_duration)end_timetime.strftime(%H:%M:%S)print(f[{end_time}] 进程{process_id}任务完成 (耗时{work_duration}秒)。)if__name____main__:# 1. 在主进程中创建信号量指定最大并发数为 3# 这就像创建了一个有 3 把钥匙的锁max_concurrent3semaphoremultiprocessing.Semaphore(max_concurrent)# 2. 创建并启动 10 个工作进程processes[]foriinrange(10):# 重要将信号量对象作为参数传递给子进程pmultiprocessing.Process(targetworker,args(i,semaphore))processes.append(p)p.start()# 3. 等待所有子进程结束forpinprocesses:p.join()print(所有任务执行完毕。)代码详解创建信号量semaphore multiprocessing.Semaphore(3)创建了一个允许3个进程同时进入临界区的信号量。传递信号量在创建Process时将semaphore作为参数传入worker函数。这是确保所有进程共享同一个信号量的关键。控制并发在worker函数中with semaphore:语句块内的代码就是临界区。任何时候最多只有3个进程能同时执行其中的代码。模拟任务time.sleep()模拟了进程的实际工作。可能的输出结果部分[14:23:01] 进程 0 开始执行任务... [14:23:01] 进程 1 开始执行任务... [14:23:01] 进程 2 开始执行任务... [14:23:03] 进程 1 任务完成 (耗时 2秒)。 [14:23:03] 进程 3 开始执行任务... # 进程1释放信号量进程3立刻开始 [14:23:04] 进程 2 任务完成 (耗时 3秒)。 [14:23:04] 进程 4 开始执行任务... ...从输出中可以看到开始执行任务的消息不会连续出现超过3次。每当一个进程完成并释放信号量后下一个等待的进程便会立即获取并开始执行。信号量 vs 进程池 (multiprocessing.Pool)这两种方式都可以控制并发但适用场景不同Semaphore更灵活可以精确控制代码中任意一个代码块的并发数而不仅仅是整个任务函数。Pool更高层主要用于管理一组同质任务的并发执行。如果你的需求是“同时最多运行N个任务”Pool是更简单的选择。如果你的需求是“在任务执行过程中某个特定资源的访问并发数不能超过N”那么Semaphore是更合适的工具。总结核心思想信号量通过一个计数器来控制对共享资源的并发访问数量。关键用法在if __name__ __main__:块中创建multiprocessing.Semaphore(N)并作为参数传递给子进程。最佳实践使用with semaphore:语句管理信号量的获取和释放避免死锁。适用场景限制对有限资源如数据库连接、网络带宽、特定硬件的并发访问。