在 Python 的异步编程中,asyncio
提供了一些强大的同步原语,可以帮助开发者在异步任务之间共享资源、协调状态以及避免竞争条件。本文将详细介绍其中的四种核心同步原语:Lock
、Event
、Condition
和 Semaphore
。
1. Lock
(锁)
Lock
是最基本的同步原语,用于在多个协程之间确保共享资源的互斥访问。asyncio.Lock
的使用方式类似于线程中的 threading.Lock
,但它是异步的。
使用场景
- 确保一个协程在访问共享资源时不会被其他协程打扰。
代码示例
import asyncio
lock = asyncio.Lock()
shared_resource = 0
async def task(name):
global shared_resource
print(f"{name} 等待锁...")
async with lock: # 使用异步锁
print(f"{name} 获得锁!")
shared_resource += 1
await asyncio.sleep(1) # 模拟工作
print(f"{name} 释放锁!")
async def main():
await asyncio.gather(task("任务1"), task("任务2"))
asyncio.run(main())
输出示例
任务1 等待锁...
任务2 等待锁...
任务1 获得锁!
任务1 释放锁!
任务2 获得锁!
任务2 释放锁!
2. Event
(事件)
Event
是一种简单的同步原语,用于在协程之间传递信号。一个协程可以等待某个事件发生,而另一个协程可以设置事件,从而唤醒所有等待的协程。
使用场景
- 用于在协程间同步某些状态,比如触发信号或通知。
代码示例
import asyncio
event = asyncio.Event()
async def waiter():
print("等待事件...")
await event.wait() # 等待事件被设置
print("事件触发了!")
async def setter():
print("准备触发事件...")
await asyncio.sleep(2)
event.set() # 触发事件
print("事件已触发!")
async def main():
await asyncio.gather(waiter(), setter())
asyncio.run(main())
输出示例
等待事件...
准备触发事件...
事件已触发!
事件触发了!
3. Condition
(条件变量)
Condition
是更高级的同步原语,允许协程等待某个条件满足后继续执行。它可以在某些复杂的状态控制下非常有用。
使用场景
- 多个协程需要在特定条件下协调工作。
代码示例
import asyncio
condition = asyncio.Condition()
shared_queue = []
async def producer():
async with condition:
print("生产者添加项目...")
shared_queue.append(1) # 添加项目到共享队列
condition.notify() # 通知等待的消费者
print("生产者通知消费者")
async def consumer():
async with condition:
while not shared_queue:
print("消费者等待项目...")
await condition.wait() # 等待生产者通知
print("消费者消费项目:", shared_queue.pop(0))
async def main():
await asyncio.gather(consumer(), producer())
asyncio.run(main())
输出示例
消费者等待项目...
生产者添加项目...
生产者通知消费者
消费者消费项目: 1
4. Semaphore
(信号量)
Semaphore
是一种计数器,限制同时运行的协程数量。asyncio.Semaphore
可以用来控制资源的最大并发访问数。
使用场景
- 控制并发量,比如限制同时处理的网络请求数量。
代码示例
import asyncio
semaphore = asyncio.Semaphore(2)
async def task(name):
async with semaphore: # 每次最多允许两个任务执行
print(f"{name} 开始执行")
await asyncio.sleep(2)
print(f"{name} 执行完成")
async def main():
await asyncio.gather(task("任务1"), task("任务2"), task("任务3"), task("任务4"))
asyncio.run(main())
输出示例
任务1 开始执行
任务2 开始执行
任务1 执行完成
任务2 执行完成
任务3 开始执行
任务4 开始执行
任务3 执行完成
任务4 执行完成
总结
asyncio
的同步原语为异步任务之间的协作提供了强大的工具:
Lock
:确保共享资源的互斥访问。Event
:在协程之间传递触发信号。Condition
:等待某个条件满足后继续执行。Semaphore
:限制协程的最大并发数。
通过灵活使用这些同步原语,可以有效解决异步编程中的竞争和协调问题,为复杂的异步应用提供更强的控制力。