Python中的异步任务同步原语:asyncio.Lock、Semaphore、Event与Condition
字数 711 2025-11-16 02:06:26

Python中的异步任务同步原语:asyncio.Lock、Semaphore、Event与Condition

在异步编程中,当多个协程需要访问共享数据或协调执行顺序时,需要使用同步原语来避免竞态条件。asyncio提供了多种同步机制,它们的设计理念与线程同步原语相似,但专门针对异步环境优化。

1. 异步锁(asyncio.Lock)

  • 作用:确保同一时间只有一个协程可以进入临界区
  • 实现原理:内部维护一个等待队列,协程获取锁时若锁已被占用,则挂起并加入队列
import asyncio

class SharedCounter:
    def __init__(self):
        self.value = 0
        self.lock = asyncio.Lock()
    
    async def increment(self):
        async with self.lock:  # 自动获取和释放锁
            temp = self.value
            await asyncio.sleep(0.1)  # 模拟IO操作
            self.value = temp + 1

# 不使用锁会导致竞态条件:多个协程可能读取到相同的初始值

2. 信号量(asyncio.Semaphore)

  • 作用:限制同时访问资源的协程数量
  • 核心机制:维护一个计数器,acquire时减1,release时加1
async def limited_worker(semaphore, id):
    async with semaphore:  # 最多允许3个协程同时执行
        print(f"Worker {id} started")
        await asyncio.sleep(1)
        print(f"Worker {id} finished")

async def main():
    semaphore = asyncio.Semaphore(3)  # 并发上限为3
    tasks = [limited_worker(semaphore, i) for i in range(5)]
    await asyncio.gather(*tasks)

3. 事件(asyncio.Event)

  • 作用:允许协程等待某个事件发生
  • 状态机制:初始为未设置,set()后唤醒所有等待者
async def waiter(event):
    print("等待事件触发...")
    await event.wait()  # 阻塞直到event被设置
    print("事件已触发,继续执行")

async def setter(event):
    await asyncio.sleep(2)
    event.set()  # 唤醒所有等待的协程

async def main():
    event = asyncio.Event()
    await asyncio.gather(waiter(event), setter(event))

4. 条件变量(asyncio.Condition)

  • 作用:基于某些条件协调多个协程的执行
  • 高级特性:结合了Lock和Event的功能,支持条件等待和通知
class BoundedBuffer:
    def __init__(self, capacity):
        self.capacity = capacity
        self.buffer = []
        self.condition = asyncio.Condition()
    
    async def put(self, item):
        async with self.condition:
            # 等待缓冲区有空间
            while len(self.buffer) >= self.capacity:
                await self.condition.wait()
            
            self.buffer.append(item)
            self.condition.notify_all()  # 通知消费者
    
    async def get(self):
        async with self.condition:
            # 等待缓冲区有数据
            while len(self.buffer) == 0:
                await self.condition.wait()
            
            item = self.buffer.pop(0)
            self.condition.notify_all()  # 通知生产者
            return item

5. 原理解析与使用要点

  • 非阻塞设计:所有异步同步原语在无法立即获取时都会挂起当前协程,让出事件循环
  • 公平性保证:等待队列通常采用FIFO顺序,避免饥饿现象
  • 超时机制:支持带超时的wait方法,防止永久阻塞
  • 与线程原语的区别:asyncio原语不能在线程间使用,线程原语会阻塞整个事件循环

最佳实践建议

  1. 优先使用async with语法自动管理资源获取和释放
  2. 锁的持有时间应尽可能短,避免影响并发性能
  3. 条件变量的等待应放在while循环中,防止虚假唤醒
  4. 注意避免死锁:确保获取和释放的顺序一致性
Python中的异步任务同步原语:asyncio.Lock、Semaphore、Event与Condition 在异步编程中,当多个协程需要访问共享数据或协调执行顺序时,需要使用同步原语来避免竞态条件。asyncio提供了多种同步机制,它们的设计理念与线程同步原语相似,但专门针对异步环境优化。 1. 异步锁(asyncio.Lock) 作用 :确保同一时间只有一个协程可以进入临界区 实现原理 :内部维护一个等待队列,协程获取锁时若锁已被占用,则挂起并加入队列 2. 信号量(asyncio.Semaphore) 作用 :限制同时访问资源的协程数量 核心机制 :维护一个计数器,acquire时减1,release时加1 3. 事件(asyncio.Event) 作用 :允许协程等待某个事件发生 状态机制 :初始为未设置,set()后唤醒所有等待者 4. 条件变量(asyncio.Condition) 作用 :基于某些条件协调多个协程的执行 高级特性 :结合了Lock和Event的功能,支持条件等待和通知 5. 原理解析与使用要点 非阻塞设计 :所有异步同步原语在无法立即获取时都会挂起当前协程,让出事件循环 公平性保证 :等待队列通常采用FIFO顺序,避免饥饿现象 超时机制 :支持带超时的wait方法,防止永久阻塞 与线程原语的区别 :asyncio原语不能在线程间使用,线程原语会阻塞整个事件循环 最佳实践建议 : 优先使用async with语法自动管理资源获取和释放 锁的持有时间应尽可能短,避免影响并发性能 条件变量的等待应放在while循环中,防止虚假唤醒 注意避免死锁:确保获取和释放的顺序一致性