英文:
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 的状态并设置其中的内容。
首先要明白的一点是:除非你使用 await
、async with
或 async 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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论