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

Python多进程Semaphore异常:并发控制不符预期且跨平台不一致

问题分析与解决方案

你的代码存在两个核心问题,导致跨平台表现不一致且不符合预期:

1. 语法错误:if __name__判断写错

你写的if __name__ = "___main__"是赋值语句而非判断语句,且___main__多了一个下划线(正确应为__main__)。这个错误会导致:

  • 在Linux的fork模式下,子进程会意外执行模块顶层的进程创建代码,引发逻辑混乱;
  • 在MacOS/Windows的spawn模式下,虽然不会直接引发进程爆炸,但会破坏信号量的共享逻辑。

2. 信号量未跨进程共享

你在全局作用域定义Sema,但不同平台的多进程启动机制会导致信号量无法共享:

  • Linux(默认fork):子进程继承父进程内存,但因if __name__错误,子进程会重新执行模块代码,导致信号量被重复初始化,最终出现串行执行的异常;
  • MacOS(Python3.8+默认spawn):子进程会重新导入整个模块,每个子进程都会创建独立的Semaphore(3)实例,每个信号量都允许3次acquire,但单个进程只需要1次,因此10个进程可以同时执行,出现一次性输出所有starting!的情况。

修正后的代码

使用multiprocessing.Manager创建跨进程共享的信号量,并通过参数传递给子进程,同时修正if __name__判断:

import multiprocessing
import time

def test_print(sema):
    sema.acquire()
    print("starting!")
    time.sleep(5)
    print("ending!")
    sema.release()

if __name__ == "__main__":
    concurrency = 3
    # 使用Manager创建跨平台共享的信号量
    with multiprocessing.Manager() as manager:
        shared_sema = manager.Semaphore(concurrency)
        process_list = []
        for _ in range(10):
            p = multiprocessing.Process(target=test_print, args=(shared_sema,))
            p.start()
            process_list.append(p)
        # 等待所有进程执行完毕
        for p in process_list:
            p.join()

为什么这样能解决问题

  • Manager.Semaphore是真正跨进程共享的,无论fork还是spawn模式,所有子进程都会使用同一个信号量实例;
  • 正确的if __name__ == "__main__"确保只有主进程会创建子进程,避免子进程重复执行模块代码;
  • 通过args传递信号量,而非依赖全局变量,确保子进程使用的是主进程创建的共享实例,符合你的预期(最多3个进程同时执行)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 19:27:35