首页 > 解决方案 > 工作变量如何与 asyncio 中的任务一起使用?

问题描述

在学习 asyncio 的过程中,我犯了一个错误,将变量“task1”链接了 3 次。

import asyncio
import time

async def say_after(delay, what):
    await asyncio.sleep(delay)
    print(what)

async def main():
    print(f"start at {time.strftime('%X')}")
    task1 = asyncio.create_task(say_after(1, 'a'))
    task1 = asyncio.create_task(say_after(2, 'aba'))
    task1 = asyncio.create_task(say_after(3, 'faf'))

    await task1
    #await task2
    print(f"finished at {time.strftime('%X')}")

asyncio.run(main())

但是当我运行代码时,我得到了这个输出

start at 19:05:19

a

aba

faf

finished at 19:05:22

为什么它不只打印最后创建的任务?为什么第一个和第二个任务没有清除?

在清晰的python中,如果我这样写:

page = 0
page = 1
page = 2

print(page)

我会得到“2”,因为之前指向对象的链接将从内存中删除。

为什么那里不一样?这个怎么运作?

标签: python-asyncio

解决方案


您正在启动三个任务并等待三个任务中最慢的一个完成。

await task1没有运行任务,它正在等待分配给的第三个任务对象task1完成。其他两个任务仍然存在于事件循环中并且仍在运行,它们首先完成,因为它们更快。

另一种看待这个问题的方法是稍微修改你的代码。这将按照您的预期开始,然后抛出错误,因为程序在较慢的任务之前完成。

    task1 = asyncio.create_task(say_after(3, 'a'))     # make slowest
    task1 = asyncio.create_task(say_after(2, 'aba'))
    task1 = asyncio.create_task(say_after(1, 'faf'))   # make fastest

重写你的代码就是完全删除代码,以task1=明确这await task1更多地与等待任务完成有关,而与使其运行无关。

    asyncio.create_task(say_after(1, 'a'))
    asyncio.create_task(say_after(2, 'aba'))
    asyncio.create_task(say_after(3, 'faf'))

    while len(asyncio.all_tasks()) > 1:
        await asyncio.sleep(0.1)
    # await task1

更常用的方法是收集对所有任务的引用并等待任务列表完成。

    tasks = []
    tasks.append(asyncio.create_task(say_after(3, 'a')))
    tasks.append(asyncio.create_task(say_after(2, 'aba')))
    tasks.append(asyncio.create_task(say_after(1, 'faf')))

    await asyncio.gather(*tasks)

推荐阅读