Asyncio:异常重试场景下await语句执行顺序与变量赋值的疑问
解答你的异步代码执行顺序疑问
完全不用担心这个问题——await queue_retry.put(msg)一定会等到msg = await get_messages(...)执行完成后才会执行,放入重试队列的必然是重试后获取到的新消息,不会是首次尝试的旧值。
为什么会这样?
在Python的异步编程中,await关键字的核心作用就是暂停当前协程的执行,直到被等待的异步操作完成并返回结果。换句话说,只要你是按顺序写的await语句,它们就会严格按照代码的先后顺序执行:
- 当代码执行到
msg = await get_messages(queue_item.channel, ids=queue_item.id)时,worker协程会暂时挂起,不再往下执行,直到get_messages这个异步操作完成(不管是成功拿到新消息,还是再次抛出异常)。 - 只有当
get_messages成功返回新消息后,这个返回值才会被赋值给msg变量,彻底覆盖掉之前的旧值。 - 紧接着,代码才会执行
await queue_retry.put(msg),此时msg已经是重试后的最新值,所以放入队列的肯定是新消息。
结合你的代码再梳理一遍流程
async def worker(name): queue_item = await queue.get() msg = queue_item.message # 首次获取旧消息 #.....# try: # get_message操作超时,抛出TimedOutError except errors.TimedOutError: # 第一步:等待get_messages完成,拿到新消息并覆盖msg msg = await get_messages(queue_item.channel, ids=queue_item.id) # 第二步:此时msg已经是新值,执行put操作 await queue_retry.put(msg)
额外补充:如果重试也失败了?
如果get_messages重试时还是抛出了异常,那么msg = await ...这一行会直接中断except块的执行,根本不会走到put步骤——这种情况下不会往重试队列里放任何消息,自然也不存在旧值被放入的问题。
总结一下:异步代码中,顺序编写的await语句是串行执行的,前一个操作完成后才会执行下一个,所以你完全可以确定放入重试队列的是重试后的新消息。
内容的提问来源于stack exchange,提问作者user14857172
相关产品推荐
相关产品推荐

