【Python】各类锁(Lock)详解与比较
在 Python 中,锁(Lock) 是 threading
和 multiprocessing
模块提供的同步机制,用于防止多个线程或进程同时访问共享资源,从而避免数据竞争和不一致问题。
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() |
线程间信号 | 事件触发机制 |
在多线程/多进程编程中,正确使用 锁 机制可以防止数据竞争、保持数据一致性,提高程序的可靠性和可维护性。
作者:彬彬侠