【Python】各类锁(Lock)详解与比较

在 Python 中,锁(Lock)threadingmultiprocessing 模块提供的同步机制,用于防止多个线程或进程同时访问共享资源,从而避免数据竞争和不一致问题。

1. threading.Lock()(线程锁)

用于在多线程环境下防止多个线程同时访问共享资源。

示例:多个线程访问共享变量

import threading
import time

counter = 0  # 共享变量
lock = threading.Lock()  # 创建锁

def worker(n):
    global counter
    with lock:  # 获取锁
        local_counter = counter
        time.sleep(0.1)  # 模拟某些计算
        counter = local_counter + n
        print(f"Thread {threading.current_thread().name} updated counter to {counter}")

# 创建多个线程
threads = [threading.Thread(target=worker, args=(1,)) for _ in range(5)]

# 启动线程
for t in threads:
    t.start()

# 等待所有线程完成
for t in threads:
    t.join()

print("Final counter value:", counter)
threading.Lock() 工作机制
  • lock.acquire(): 获取锁(如果锁已被占用,则阻塞)
  • lock.release(): 释放锁(让其他线程可以获取)
  • with lock:: 推荐的用法,with 语句确保锁在退出代码块时自动释放,即使发生异常。

  • 2. multiprocessing.Lock()(进程锁)

    用于多进程环境,防止多个进程同时访问共享资源。

    示例:多个进程访问共享资源

    import multiprocessing
    import time
    
    counter = multiprocessing.Value('i', 0)  # 共享变量
    lock = multiprocessing.Lock()  # 进程锁
    
    def worker(n):
        with lock:  # 获取锁
            local_counter = counter.value
            time.sleep(0.1)  # 模拟某些计算
            counter.value = local_counter + n
            print(f"Process {multiprocessing.current_process().name} updated counter to {counter.value}")
    
    # 创建多个进程
    processes = [multiprocessing.Process(target=worker, args=(1,)) for _ in range(5)]
    
    # 启动进程
    for p in processes:
        p.start()
    
    # 等待所有进程完成
    for p in processes:
        p.join()
    
    print("Final counter value:", counter.value)
    

    multiprocessing.Lock() 工作机制

  • multiprocessing.Lock()threading.Lock() 接口相同,但作用于进程间。
  • with lock: 确保进程互斥访问共享资源,防止数据不一致问题。

  • 3. RLock()(可重入锁)

    适用于递归调用同一线程多次获取锁

    import threading
    
    lock = threading.RLock()
    
    def recursive_function(n):
        if n <= 0:
            return
        with lock:  # 允许同一线程多次获取锁
            print(f"Acquired lock in recursion level {n}")
            recursive_function(n - 1)
    
    recursive_function(3)
    

    普通 Lock 不能被同一线程多次 acquire(),但 RLock() 可以!


    4. Semaphore()(信号量)

    用于限制并发访问的线程/进程数量(例如:数据库连接池)。

    import threading
    import time
    
    semaphore = threading.Semaphore(3)  # 最多允许 3 个线程同时运行
    
    def worker(n):
        with semaphore:
            print(f"Thread {n} is running")
            time.sleep(2)
            print(f"Thread {n} finished")
    
    threads = [threading.Thread(target=worker, args=(i,)) for i in range(6)]
    
    for t in threads:
        t.start()
    
    for t in threads:
        t.join()
    
  • 设定 Semaphore(3),最多 3 个线程能同时进入。
  • 常用于连接池、资源管理、并发限制等场景。

  • 5. Condition()(条件变量)

    用于线程间协调,例如一个线程需要等另一个线程完成某个操作后才能继续。

    import threading
    
    condition = threading.Condition()
    shared_data = None
    
    def consumer():
        global shared_data
        with condition:
            print("Consumer waiting...")
            condition.wait()  # 等待生产者通知
            print(f"Consumer received: {shared_data}")
    
    def producer():
        global shared_data
        with condition:
            shared_data = "Data ready!"
            print("Producer produced data, notifying consumer...")
            condition.notify()  # 通知消费者
    
    t1 = threading.Thread(target=consumer)
    t2 = threading.Thread(target=producer)
    
    t1.start()
    t2.start()
    
    t1.join()
    t2.join()
    

    使用 Condition() 解决“生产者-消费者”问题。


    6. Event()(事件)

    线程间的简单信号通知机制(相当于全局 flag)

    import threading
    import time
    
    event = threading.Event()
    
    def worker():
        print("Worker waiting for event...")
        event.wait()  # 等待事件被 set
        print("Worker received event signal!")
    
    def set_event():
        time.sleep(3)
        event.set()  # 触发事件
    
    threading.Thread(target=worker).start()
    threading.Thread(target=set_event).start()
    

    适用于:

  • 线程间同步
  • 控制多个线程的启动时机

  • 总结

    锁类型 适用范围 主要作用
    threading.Lock() 线程间同步 互斥访问共享资源
    multiprocessing.Lock() 进程间同步 互斥访问进程共享资源
    threading.RLock() 递归调用 允许同一线程多次获取锁
    threading.Semaphore(n) 线程池/连接池 限制并发线程数
    threading.Condition() 线程间通信 等待/通知机制(生产者-消费者)
    threading.Event() 线程间信号 事件触发机制

    在多线程/多进程编程中,正确使用 机制可以防止数据竞争、保持数据一致性,提高程序的可靠性和可维护性。

    作者:彬彬侠

    物联沃分享整理
    物联沃-IOTWORD物联网 » 【Python】各类锁(Lock)详解与比较

    发表回复