【问题标题】:A question about the result of asyncio & Async/Await application in python关于python中asyncio & Async/Await应用程序结果的问题
【发布时间】:2022-06-12 18:08:13
【问题描述】:

当我运行代码时:

import asyncio
async def foo(text):
    print(text)
    await asyncio.sleep(1)  
    print(text)
async def main():
    print("tim")
    task = asyncio.create_task(foo("text"))  
    await asyncio.sleep(1)
    print("finished")
asyncio.run(main())  

输出是:

tim
text
finished
text

但是,当我将 main() 函数中的睡眠时间更改为 0.5 时:

import asyncio
async def foo(text):
    print(text)
    await asyncio.sleep(1)  
    print(text)
async def main():
    print("tim")
    task = asyncio.create_task(foo("text"))  
    await asyncio.sleep(0.5)
    print("finished")
asyncio.run(main())  

输出是:

tim
text
finished

然后,当我将 main() 函数中的睡眠时间更改为 0.99 时:

import asyncio
async def foo(text):
    print(text)
    await asyncio.sleep(1)  
    print(text)
async def main():
    print("tim")
    task = asyncio.create_task(foo("text"))  
    await asyncio.sleep(0.99)
    print("finished")
asyncio.run(main())  

输出是:

tim
text
finished
text

请问为什么最后的“文本”在第一种和第三种情况下打印但在第二种情况下没有打印?谢谢。

还有一个问题:

第一种情况,如果asyncio.run()在main()函数中的print("finished")之后结束,为什么foo()任务中的print(text)仍然执行。这是因为@Paul Cornelius 的回答中所说的大约 15 毫秒的粒度吗?

此外,我在 main() 函数中添加了一个额外的 time.sleep(),因此 foo() 任务中的 await 比 main() 任务的完成更早结束。但是在这种情况下,main() 函数在 print("finished") 之后不会执行 foo() 任务:

async def foo(text):
    print(text)
    await asyncio.sleep(1)
    print(text)
async def main():
    print("tim")
    task = asyncio.create_task(foo("text"))
    await asyncio.sleep(0.5)
    time.sleep(1)
    print("finished")
asyncio.run(main())

输出是:

tim
text
finished

【问题讨论】:

    标签: python asynchronous async-await task python-asyncio


    【解决方案1】:

    一个很好的问题。

    这与asyncio.run 函数有很大关系,它做了几件事:

    • 它创建并启动一个事件循环
    • 它将其参数 (main()) 转换为一个任务并安排它通过事件循环执行
    • 等待任务完成
    • 它关闭事件循环,从任务返回结果

    在这一切完成之前,run() 函数不会返回。

    在您的三个案例中,我认为第一个非常简单,不需要太多解释。主要功能至少需要 1 秒才能完成。两个任务(main 和 foo)在它们的 await 语句中来回产生。

    在第二种情况下,主要任务只需 0.5 秒即可运行。此时主要任务完成,因此 asyncio.run() 函数返回。 foo 任务仍在运行,但 asyncio.run() 在事件循环退出时关闭它。所以 foo 任务永远不会完成,你也永远不会看到第二个“文本”输出。 main 和 foo 之间没有层级关系,尽管 main() 启动了 foo();所有任务都是对等的。所以 main() 不会等待 foo() 完成。

    第三种情况是最有趣的。你会认为第三种情况和第二种情况是一样的,因为 0.99 秒小于 1.0 秒。但是 asyncio 中的时间并不准确。我的经验是,至少在 Windows 上,粒度约为 15 毫秒或稍多一点。因此,出于所有实际目的,0.99 秒 == 1.0 秒。作为一个实验,我把你的 0.99s 改成 0.98s 并且发生了一件有趣的事情:程序并不总是产生相同的输出!有时它会打印两次“文本”,就像在您的第一个示例中一样,有时会打印一次,例如您的第二个示例。因此,根据内部时钟“滴答”的时间,0.98 秒有时小于 1.0 秒,有时等于。

    【讨论】:

    • 谢谢保罗。它真的很有用。现在有一件事让我感到困惑(如问题中所编辑)。第一种情况,main()函数执行完print("finished")后,如果main任务完成了,所以asyncio.run()函数返回,为什么foo()任务中的print(text)仍在执行。我想我在这里误解了一些东西......(在问题中添加了一个例子)。谢谢。
    猜你喜欢
    • 2018-09-24
    • 1970-01-01
    • 1970-01-01
    • 2020-03-25
    • 1970-01-01
    • 1970-01-01
    • 2013-01-12
    • 2013-05-16
    • 1970-01-01
    相关资源
    最近更新 更多