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

基于唯一标识的多进程目录Git操作锁实现求助

解决多进程下基于资源标识的互斥锁问题

你遇到的核心问题是每个进程单独创建的Lock对象是进程本地的,完全独立,所以根本无法实现跨进程的互斥。下面给你两个更优的方案,完美解决这个问题:

方案一:用multiprocessing.Manager共享锁字典

multiprocessing.Manager可以创建跨进程共享的对象,我们用它来维护一个字典——键是你的资源标识(比如'a'、'b'),值是对应的Lock对象。这样所有进程都会访问同一个锁字典,同一标识的进程会拿到同一个锁,自然实现互斥。

代码示例

from multiprocessing import Lock, Process, Manager
import os
import time

def work_on(name: str, lock_dict):
    # 确保每个标识对应唯一的锁(原子性的获取或创建)
    lock = lock_dict.get(name)
    if not lock:
        lock = Lock()
        lock_dict[name] = lock
    with lock:
        print(int(time.time() % 100), os.getpid(), f"working on {name}")
        time.sleep(5)
        print(int(time.time() % 100), os.getpid(), f"done with {name}")

if __name__ == "__main__":
    res = ['a', 'b']
    processes = []
    # 创建跨进程共享的字典
    with Manager() as manager:
        lock_dict = manager.dict()
        for r in res:
            p1 = Process(target=work_on, args=(r, lock_dict))
            p1.start()
            p2 = Process(target=work_on, args=(r, lock_dict))
            p2.start()
            processes += [p1, p2]
        
        for p in processes:
            p.join()

效果说明

这个方案会让同一标识的进程串行执行,不同标识的进程并行执行,完全符合你的预期。典型输出类似:

67 48687 working on a
67 48689 working on b
72 48687 done with a
72 48689 done with b
72 48688 working on a
72 48690 working on b
77 48688 done with a
77 48690 done with b

方案二:用文件系统原子锁(高性能/跨场景)

如果不想依赖Manager的进程通信开销,或者需要支持跨语言、跨进程的锁,可以用文件系统的原子锁机制。利用操作系统对文件锁的原子性支持,彻底解决手动写文件的竞态问题,性能也更优。

Unix/Linux 下用fcntl实现

import fcntl
import os
import time
from multiprocessing import Process

def work_on(name: str):
    lock_file_path = f"./.lock_{name}"
    # 打开锁文件(不存在则自动创建)
    with open(lock_file_path, 'w') as lock_file:
        try:
            # 加独占锁,阻塞直到拿到锁
            fcntl.flock(lock_file, fcntl.LOCK_EX)
            print(int(time.time() % 100), os.getpid(), f"working on {name}")
            time.sleep(5)
            print(int(time.time() % 100), os.getpid(), f"done with {name}")
        finally:
            # 释放锁(文件关闭时也会自动释放,这里显式写是为了清晰)
            fcntl.flock(lock_file, fcntl.LOCK_UN)

if __name__ == "__main__":
    res = ['a', 'b']
    processes = []
    for r in res:
        p1 = Process(target=work_on, args=(r,))
        p1.start()
        p2 = Process(target=work_on, args=(r,))
        p2.start()
        processes += [p1, p2]
    
    for p in processes:
        p.join()

Windows 下用标准库实现

如果需要支持Windows,可以用win32file模块的锁机制:

import win32file
import win32con
import os
import time
from multiprocessing import Process

def work_on(name: str):
    lock_file_path = f"./.lock_{name}"
    # 创建或打开文件,指定不共享模式
    handle = win32file.CreateFile(
        lock_file_path,
        win32con.GENERIC_READ | win32con.GENERIC_WRITE,
        0,  # 禁止其他进程共享访问
        None,
        win32con.OPEN_ALWAYS,
        win32con.FILE_ATTRIBUTE_NORMAL,
        None
    )
    try:
        # 加独占锁
        win32file.LockFileEx(handle, win32con.LOCKFILE_EXCLUSIVE_LOCK, 0, -0x10000, None)
        print(int(time.time() % 100), os.getpid(), f"working on {name}")
        time.sleep(5)
        print(int(time.time() % 100), os.getpid(), f"done with {name}")
    finally:
        # 释放锁并关闭文件句柄
        win32file.UnlockFileEx(handle, 0, -0x10000, None)
        win32file.CloseHandle(handle)

if __name__ == "__main__":
    res = ['a', 'b']
    processes = []
    for r in res:
        p1 = Process(target=work_on, args=(r,))
        p1.start()
        p2 = Process(target=work_on, args=(r,))
        p2.start()
        processes += [p1, p2]
    
    for p in processes:
        p.join()

方案对比

  • Manager字典锁:纯Python标准库,跨平台,实现简单,适合纯Python多进程场景;缺点是依赖Manager进程,有一定的通信开销。
  • 文件原子锁:性能更高,支持跨进程/跨语言,不需要依赖Python的multiprocessing机制;缺点是需要处理平台差异,Unix和Windows的API不同。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:41:56