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

Python多进程多锁为何比单锁运行更慢?求技术解析

Python多进程锁实验疑问:多锁反而比单锁慢?

我正在做Python multiprocessing实验,代码需要并发修改3个跨进程共享变量(dict、float、int)。按锁机制的逻辑,给每个变量分配单独的锁应该更高效,能避免进程因为修改无关变量而等待。但实际测试下来,单锁版本耗时2.1秒,多锁版本反而耗时2.85秒,比单锁还慢。

单锁版本代码

import multiprocessing as mp
import numpy as np
import time

class ToyClass:
    def __init__(self, shared_a, shared_b):
        self.a = shared_a
        self.b = shared_b

    def update_a(self, key, n, lock):
        with lock:
            if key not in self.a:
                self.a[key] = np.zeros(4)
            self.a[key][n] += 1

    def update_b(self, lock):
        with lock:
            self.b.value = max(0.1, self.b.value - 0.01)

def run_episode(toy, counter, lock):
    key = np.random.randint(100)
    n = np.random.randint(4)
    toy.update_a(key, n, lock)
    toy.update_b(lock)
    with lock:
        counter.value += 1

if __name__ == "__main__":
    num_episodes = 1000
    num_processes = 4

    t0 = time.time()

    with mp.Manager() as manager:
        shared_a = manager.dict()
        shared_b = manager.Value('d', 0)
        counter = manager.Value('i', 0)

        toy = ToyClass(shared_a=shared_a, shared_b=shared_b)

        # Single lock
        lock = manager.Lock()

        pool = mp.Pool(processes=num_processes)

        for _ in range(num_episodes):
            pool.apply_async(run_episode, args=(toy, counter, lock))

        pool.close()
        pool.join()

    tf = time.time()

    print(f"Time to compute single lock: {tf - t0} seconds")

多锁版本代码

import multiprocessing as mp
import numpy as np
import time


class ToyClass:  ## Same definition as for single lock
    def __init__(self, shared_a, shared_b):
        self.a = shared_a
        self.b = shared_b

    def update_a(self, key, n, lock):
        with lock:
            if key not in self.a:
                self.a[key] = np.zeros(4)
            self.a[key][n] += 1 

    def update_b(self, lock):
        with lock:
            self.b.value = max(0.1, self.b.value - 0.01)

def run_episode(toy, counter, lock_a, lock_b, lock_count):
    key = np.random.randint(100)
    n = np.random.randint(4)
    toy.update_a(key, n, lock_a)
    toy.update_b(lock_b)
    with lock_count:
        counter.value += 1

if __name__ == "__main__":
    num_episodes = 1000
    num_processes = 4

    t0 = time.time()

    with mp.Manager() as manager:
        shared_a = manager.dict()
        shared_b = manager.Value('d', 0)
        counter = manager.Value('i', 0)

        toy = ToyClass(shared_a=shared_a, shared_b=shared_b)

        # 3 locks for 3 shared variables
        lock_a = manager.Lock()
        lock_b = manager.Lock()
        lock_count = manager.Lock()

        pool = mp.Pool(processes=num_processes)

        for _ in range(num_episodes):
            pool.apply_async(run_episode, args=(toy, counter, lock_a, lock_b, lock_count))

        pool.close()
        pool.join()

    tf = time.time()

    print(f"Time to compute multi-lock: {tf - t0} seconds")

疑问

请问我忽略了什么?是不是锁切换的计算开销超过了潜在收益?锁不就是个标记吗,为什么会出现这种情况?

注:我知道单进程/线程运行更快,这个实验就是为了理解多进程的缺点才做的。


问题解答

核心原因:跨进程锁的额外开销 + 实验场景不匹配

  1. Manager.Lock是跨进程远程锁,IPC开销大
    你用的mp.Manager()创建的锁不是本地线程锁,而是依赖Manager服务进程中转的跨进程锁。每次获取/释放锁都要进行进程间通信(IPC),这种通信本身就有不小的开销。单锁版本只需要3次IPC操作(分别对应update_a、update_b、counter的锁操作),但多锁版本需要3次不同锁的独立IPC,累积下来的开销直接超过了多锁带来的并发收益。

  2. 当前场景锁竞争极低,多锁优势无法体现
    你的每个run_episode里,锁的持有时间极短:只是简单的字典键检查、数组元素自增、浮点值更新、计数器加1。这种情况下,单锁的等待时间几乎可以忽略不计,反而多出来的几次锁IPC操作的开销成了主要耗时点。只有当锁持有时间很长(比如每个锁内执行1秒的计算任务)时,多锁才能让不同变量的修改并行,这时多锁的优势才会显现。

  3. 多锁带来更多内核态/用户态切换开销
    虽然锁本质是"标记",但跨进程锁的获取/释放会触发内核级的调度动作。多锁意味着更多次的内核态与用户态之间的切换,这些切换的开销远大于你想象。单锁版本中,进程拿到一次锁后可以连续完成三个操作,减少了切换次数;而多锁版本需要三次申请不同的锁,每次都可能触发调度,累积起来就导致整体变慢。

验证建议

  • 若想测试多锁的优势,可在update_a的锁内添加耗时任务(比如time.sleep(0.1)),此时单锁会让所有进程排队等待,多锁则能让不同变量的修改并行,多锁版本的耗时会显著低于单锁。
  • 如果使用本地锁(mp.Lock())而非Manager.Lock(),开销会小很多,但注意Manager创建的共享变量必须配合Manager的锁使用,否则会出现同步问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 12:57:33