asyncio中同一变量多次赋值任务为何全部执行而非仅最后一个
asyncio任务多次赋值同一变量仍全部执行的原因
普通变量赋值的运行逻辑
你举的普通变量赋值例子符合Python的通用引用规则:
page = 0 page = 1 page = 2 print(page)
对同一变量多次赋值时,旧的字面量/对象如果没有其他地方持有引用,会被Python的垃圾回收机制自动清理,最终变量只会指向最后一次赋值的对象,所以输出只有2。
asyncio Task的特殊调度逻辑
asyncio的Task对象和普通对象的区别在于,asyncio.create_task()被调用时,除了返回Task对象外,会自动将Task注册到当前运行的事件循环的内部调度队列中,事件循环会持有所有未完成Task的强引用:
- 你自己定义的
task1变量只是Task的一个额外的、非必需的引用入口 - 给
task1重新赋值,只是移除了你侧的变量对旧Task的引用,事件循环持有的引用仍然存在,旧Task不会被垃圾回收,也不会被终止,会继续被事件循环调度执行
代码运行过程拆解
你示例中的三次create_task调用,会把三个延时任务全部加入事件循环调度队列:
- 第一个任务延时1秒输出
a - 第二个任务延时2秒输出
aba - 第三个任务延时3秒输出
faf
你最后执行的await task1是等待第三个任务执行完成,总共需要3秒,这段时间足够前两个延时更短的任务全部执行完毕,所以三个打印内容都会输出,总耗时刚好3秒。
如果要验证这个逻辑,可以把await task1修改为await asyncio.sleep(1.5),你会发现只有a会被打印,剩下的两个任务会因为主协程提前结束、事件循环退出被强制终止,进一步证明任务的运行只和事件循环是否持有引用、是否有执行机会有关,和你是否用自定义变量引用它没有关系。
内容的提问来源于stack exchange,提问作者Игорь Середа
相关产品推荐
相关产品推荐

