我试图理解python的asynico模块,并在https://docs.python.org/3/library/asyncio-task.html#asyncio.create_task遇到了以下代码段
class Generic<T extends Number> {
Function<T, Boolean> f = i -> true;
public Boolean use(T n) {
return f.apply(n);
}
}
事实证明,可以简单地删除import time
import asyncio
async def say_after(delay, what):
await asyncio.sleep(delay)
print(what)
async def main():
task1 = asyncio.create_task(
say_after(1, 'hello'))
task2 = asyncio.create_task(
say_after(2, 'world'))
print('started at', time.strftime('%X'))
# Wait until both tasks are completed (should take
# around 2 seconds.)
await task1
await task2
print('finished at', time.strftime('%X'))
asyncio.run(main())
(或await task2
,但不能同时删除两者),并且代码看起来完全一样。我觉得这很违反直觉,这是怎么回事?
谢谢您的宝贵时间。
答案 0 :(得分:1)
await
不会在任务中启动协同程序,它只是告诉协同程序main
wait 来等待这两个程序。事件循环从run_until_complete
隐式开始,这意味着它将等待传递给它的Coro(main
)完成。依靠自己的生命来延长自己的生存期(通过await
)足够长的时间以确保从其内部创建的任务能够完成。
async def main():
task1 = asyncio.create_task(
say_after(1, 'hello'))
task2 = asyncio.create_task(
say_after(2, 'world'))
#await task1
#await task2
print(asyncio.all_tasks(asyncio.get_event_loop()))
# will print (added line breaks and shortened paths for readibility):
{
<Task pending coro=<main() running at C:/Users/.../lmain.py:17> cb=[_run_until_complete_cb() at C:...\lib\asyncio\base_events.py:150]>,
<Task pending coro=<say_after() running at C:/Users/.../lmain.py:5>>,
<Task pending coro=<say_after() running at C:/Users/.../lmain.py:5>>
}
如您所见,所有三个花冠都没有await
运行任何东西。只是两个say_after
花费的时间比main
隐含地控制事件循环运行多长时间的main
长。
如果您让async def main():
task1 = asyncio.create_task(
say_after(1, 'hello'))
task2 = asyncio.create_task(
say_after(2, 'world'))
print('started at', time.strftime('%X'))
#await task1
#await task2
await asyncio.sleep(5)
print('finished at', time.strftime('%X'))
# output
started at 15:31:48
hello
world
finished at 15:31:53
等待循环中的工作足够长的时间,则两项任务都将完成:
await
因此,当您测试注释以上task1
和/或task2
的{{1}}时,完成哪个任务(如果有)基本上只是时间问题,主要受以下因素影响:硬件,操作系统以及可能的运行时(即IDE与Shell)。
P.S。任务仅包含three states:pending
,cancelled
和finished
。每个任务在创建后立即处于状态pending
,并保持该状态,直到包装在其中的协同程序终止(以任何方式终止)或被控制它的事件循环取消为止。
答案 1 :(得分:1)
您提出了三种不同的情况:
await
条语句(全部注释掉)await task1
(注释掉第二个)await task2
(注释掉第一个)这是您的脚本;仅出于说明目的,将task2
上的睡眠时间延长一点。
# tasktest.py
import time
import asyncio
async def say_after(delay, what):
await asyncio.sleep(delay)
print(what)
async def main():
task1 = asyncio.create_task(
say_after(1, 'hello'))
task2 = asyncio.create_task(
say_after(3, 'world'))
print('started at', time.strftime('%X'))
await task1
# await task2
print('finished at', time.strftime('%X'))
asyncio.run(main())
await
语句这是asyncio.run()
的鲜肉:
loop = events.new_event_loop()
try:
events.set_event_loop(loop)
loop.set_debug(debug)
return loop.run_until_complete(main) # < -----
finally:
try:
_cancel_all_tasks(loop) # < -----
loop.run_until_complete(loop.shutdown_asyncgens())
finally:
events.set_event_loop(None)
loop.close()
重要的是,仅 循环关心main()
已完成,然后取消了与正在运行的事件循环关联的所有其他任务。 (每个任务在指定后都是tied to个事件循环。)
如果您定义main()
时没有任何await
语句,则create_task()
计划要执行的任务,但是main()
不会等待其中任何一个完成。< / p>
await task1
设置:
await task1
# await task2
输出:
(base_py37) $ python3 tasktest.py
started at 11:06:46
hello
finished at 11:06:47
这两个任务都从待处理变为正在运行,但只有task1
完成,因为main()
仅等待大约1秒钟的任务,而该时间不足以使task2
运行。 sup> * (请注意,main()
仅花费1秒。)
await task2
设置:
# await task1
await task2
输出:
(base_py37) $ python3 tasktest.py
started at 11:08:37
hello
world
finished at 11:08:40
这两个任务都从待处理变为正在运行,现在task1
和task2
都完成了,因为main()
等待的任务大约需要3秒钟,足以使两个任务都能运行完成。
*这至少适用于我的设置(Mac OSX,...),但是如此处其他答案所述,在其他设置上,计时可能会有所不同,并且如果任务运行时间相似,两者都可能会在第2种情况下运行。