asyncio.Future.done()在任务完成时为什么没有设置为True?

huangapple go评论54阅读模式
英文:

Why is asyncio.Future.done() not set to True when the task is done?

问题

在这个示例代码中,创建了一个asyncio.Future并运行它。然而,一旦它完成,状态就没有设置为"done"。

这导致result.done()在第二次睡眠后设置为False的原因是,loop.run_in_executor返回一个asyncio.Future,但它的状态不会在执行线程中的test函数完成时自动设置为"done"。相反,它将在await result语句执行时设置为"done",这是因为这时候才等待了执行线程中的结果。所以在第二次睡眠之前,result.done()仍然为False

英文:

In this example code a asyncio.Future is created and run. However the state is not set to done once it is complete.

import asyncio
from concurrent.futures.thread import ThreadPoolExecutor
from time import sleep

_executor = ThreadPoolExecutor(max_workers=32)

def test():
    print('starting test')
    sleep(5)
    print('ending test')

async def main():
    loop = asyncio.get_running_loop()
    result = loop.run_in_executor(_executor, test)

    sleep(3)
    print('sleep 1 complete')
    print(f'{result.done()=}')

    sleep(3)
    print('sleep 2 complete')
    print(f'{result.done()=}')

    print('await result')
    await result
    print(f'{result.done()=}')

asyncio.run(main())

This results in:

starting test
sleep 1 complete
result.done()=False
ending test
sleep 2 complete
result.done()=False
await result
result.done()=True

Why is result.done() set to False after the second sleep?

答案1

得分: 1

你在代码片段的初始步骤中没有将控制权交给 asyncio 循环:asyncio 循环从未有机会检查 Future 的状态并设置其中的内容。

首先要明白的一点是:除非你使用 awaitasync withasync for 中的其中一种来将控制权传递给循环,否则无法运行与异步相关的代码。

没有所谓的,“只要休眠足够长时间,asyncio 就会启动并执行其任务”。不是的。这是单线程代码的特性之一,使用它的好处之一是让用户完全控制任务变化发生的位置。而在你的代码中,这些变化仅在倒数第二行的 await result 中发生。

是的,在这种情况下,任务本身被分派到执行器中的另一个线程,并在那里运行 - 但是异步循环会检查任务是否完成,设置 Future 中的属性等等。

英文:

You are not yielding the control to the asyncio loop in the first steps in your snippet: the asyncio loop never gets a chance to check the Future status and set whatever in it.

For one take away, make sure you understand this: no async related code can run unless you pass control to the loop with one of await, async with or async for

There is no, "with enough sleep, eventually the asyncio will kick in and do its thing". No. It is single threaded code, and one of the benefits of using it is giving the user full control of where the task changes take place. And in your code, they take place just in the second-to-last line with await result.

Yes, in this case, the task itself is dispatched to another thread in the executor, and it runs there - but it is the asyncio loop which checks for the task completion, set the attributes in the Future, and so on.

huangapple
  • 本文由 发表于 2023年5月25日 15:47:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/76329988.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定