asyncio协程触发后暂停至条件满足及锁使用正确性咨询
问题解答
1. 用条件cond2替代10秒延迟的实现方案
直接使用asyncio.Condition这个协程同步原语即可,它专门用于实现"等待某个条件满足后再继续执行"的逻辑,步骤如下:
- 创建一个所有协程共享的
asyncio.Condition实例 - 当cond1触发时,所有协程进入
async with condition:代码块,调用await condition.wait()挂起,直到cond2被触发 - 当cond2满足时(比如某个状态变更、外部事件触发),在对应的逻辑里执行
async with condition:后调用condition.notify_all(),唤醒所有等待的协程
示例代码:
import asyncio # 模拟cond1和cond2的检查逻辑 def check_cond1(run_count): return run_count >= 3 def check_cond2(trigger_flag): return trigger_flag async def coro1(condition, stop_event): run_count = 0 while not stop_event.is_set(): print("coro1 运行中") await asyncio.sleep(1) run_count += 1 if check_cond1(run_count): print("cond1触发,等待cond2") async with condition: await condition.wait() # 挂起直到cond2满足 print("coro1 恢复运行") async def coro2(condition, stop_event): trigger_flag = False run_count = 0 while not stop_event.is_set(): print("coro2 运行中") await asyncio.sleep(1) run_count += 1 if check_cond1(run_count): print("coro2触发cond1,等待cond2") async with condition: await condition.wait() # 模拟cond2触发逻辑(比如运行5次后触发) if run_count >= 5: trigger_flag = True if check_cond2(trigger_flag): async with condition: condition.notify_all() # 唤醒所有等待的协程 print("cond2满足,唤醒所有协程") stop_event.set() async def main(): condition = asyncio.Condition() stop_event = asyncio.Event() await asyncio.gather(coro1(condition, stop_event), coro2(condition, stop_event)) if __name__ == "__main__": asyncio.run(main())
condition.wait()会自动释放内部锁并挂起协程,收到通知后会重新获取锁再恢复执行,完全替代固定延迟的逻辑。
2. asyncio.Lock的正确性排查
你遇到的IO写入干扰,大概率是Lock的使用方式有问题,常见错误及修正方案:
- Lock实例未共享:如果每个协程自己创建Lock,完全起不到互斥作用,必须让所有需要同步的协程使用同一个Lock实例
- 原子操作块包裹不全:文件写入的完整流程(打开、写入、关闭)必须全部放在
async with lock:块内,不能只锁部分步骤 - 混用同步IO和异步代码:如果用普通
open()做同步写入,即使加了Lock,同步IO会阻塞事件循环,导致协程调度异常,建议用aiofiles这类异步文件库配合Lock
正确的异步文件写入+Lock示例:
import asyncio import aiofiles async def safe_write(lock, filename, content): # 用Lock包裹整个写入操作 async with lock: async with aiofiles.open(filename, 'a', encoding='utf-8') as f: await f.write(content + '\n') async def coro_a(lock): for i in range(5): await safe_write(lock, 'log.txt', f'协程A:第{i+1}行内容') await asyncio.sleep(0.3) async def coro_b(lock): for i in range(5): await safe_write(lock, 'log.txt', f'协程B:第{i+1}行内容') await asyncio.sleep(0.3) async def main(): # 所有协程共享同一个Lock lock = asyncio.Lock() await asyncio.gather(coro_a(lock), coro_b(lock)) if __name__ == "__main__": asyncio.run(main())
这样就能保证同一时间只有一个协程执行文件写入,避免内容错乱。
内容的提问来源于stack exchange,提问作者bugrahaskan
相关产品推荐
相关产品推荐

