异步、等待和无限循环

Posted

技术标签:

【中文标题】异步、等待和无限循环【英文标题】:Asyncio, await and infinite loops 【发布时间】:2017-12-12 10:25:01 【问题描述】:
async def start(channel):
    while True:
        m = await client.send_message(channel, "Generating... ")
        generator.makeFile()
        with open('tmp.png', 'rb') as f:
            await client.send_file(channel, f) 
        await client.delete_message(m)
        await asyncio.sleep(2)

我有一个每 2 秒运行一次任务的不和谐机器人。我尝试为此使用无限循环,但脚本因Task was destroyed but it is still pending! 而崩溃我已经阅读了有关异步协程的信息,但我发现的示例中没有一个使用await。例如,是否可以通过使用await 运行协程来避免此错误?

【问题讨论】:

await 在这里不是问题。更多while True 也是定期调用的常用方式(***.com/questions/37512182/…)。显示你是如何执行那个函数的,你是否试图在代码中停止这个任务? 【参考方案1】:

Task was destroyed but it is still pending! 是当您调用loop.close() 时收到的警告,当您的脚本中的某些tasks 未完成时。通常你应该避免这种情况,因为未完成的任务可能不会释放一些资源。您需要在事件循环关闭之前等待任务完成或cancel。

由于您有无限循环,您可能需要取消任务,例如:

import asyncio
from contextlib import suppress


async def start():
    # your infinite loop here, for example:
    while True:
        print('echo')
        await asyncio.sleep(1)


async def main():
    task = asyncio.Task(start())

    # let script some thime to work:
    await asyncio.sleep(3)

    # cancel task to avoid warning:
    task.cancel()
    with suppress(asyncio.CancelledError):
        await task  # await for task cancellation


loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
try:
    loop.run_until_complete(main())
finally:
    loop.run_until_complete(loop.shutdown_asyncgens())
    loop.close()

有关任务的更多信息,另请参阅this answer。

【讨论】:

That answer 完美解决了,谢谢。此示例运行良好,但似乎要求无限循环将在某一点或另一点停止。 如果我在 main func 中以相同的顺序等待两个异步任务(task1 和 task2),则 task1 有一个 while true 循环,并在该 while 循环内再调用一个异步任务(task3)。在这种情况下,执行是否会传递给 task2? @y_159 抱歉,我很难跟上。你有机会用代码写这个吗? @MikhailGerasimov 谢谢,我通过脚本进行了测试,即使任务包含 while True 循环,异步也可以正常工作。

以上是关于异步、等待和无限循环的主要内容,如果未能解决你的问题,请参考以下文章

为啥这个异步函数无限循环?

使用 setInterval() 的无限异步循环 [重复]

为啥计算内部的异步会产生无限循环(vue)?

如何使用 Promises 进行异步无限循环

Angular 2 - 异步管道中的无限循环

Angular 11异步验证器触发真实响应的无限循环请求