【问题标题】:Coroutine and Async / Await协程和异步/等待
【发布时间】:2020-04-29 16:22:31
【问题描述】:

我遇到了 asyncIO 问题。我想让我的程序在协程正在运行的任务时做一些事情,协程完成后退出。

我已将我的问题简化为这个 sn-p:

import time
import asyncio


async def long_task():
    time.sleep(3)
    return "DONE !"


def do_while_idle():
    loop = asyncio.get_event_loop()
    task = loop.create_task(long_task)
    while not task.done():
        time.sleep(1)
        print("IDLE")
    print(task.result())


do_while_idle()

我想要这个输出:

IDLE
IDLE
IDLE
DONE !

提前致谢。

【问题讨论】:

  • 不要在异步循环中使用 time.sleep(3)。使用 asyncio.sleep。

标签: python python-3.x async-await python-asyncio


【解决方案1】:

作为MisterMiyagi points out,您必须等待asyncio.sleep() 而不是调用time.sleep(),以及消除其他阻塞,例如通过将requests 的使用替换为aiohttp

要在任务运行期间执行一些空闲代码,您可以将空闲代码编写为无限循环,独立于主任务。 do_while_idle可以将idle loop作为任务启动,直接awaitlong_task(),然后直接取消idle:

import asyncio

async def long_task():
    await asyncio.sleep(3)
    return "DONE !"

async def idle():
    while True:
        await asyncio.sleep(1)
        print("IDLE")

async def do_while_idle():
    idle_task = asyncio.create_task(idle())
    print(await long_task())
    idle_task.cancel()

asyncio.run(do_while_idle())

【讨论】:

  • 正是这个!非常感谢。
【解决方案2】:

你可以这样处理:

import asyncio

async def do_while_idle():
    for _ in range(3):
        print("IDLE")
        await asyncio.sleep(1)

    return "Done stuff while idling"

async def long_task():
    await asyncio.sleep(3)
    return "DONE !"

async def main():
    task = asyncio.create_task(long_task())
    task2 = asyncio.create_task(do_while_idle())
    done, _ = await asyncio.wait({task, task2})

    if task in done:
        task2.cancel()
        print(task.result())

asyncio.run(main())

idling应该是另一个task,这个sn-p等待long_task完成,然后取消idling task。您还可以检查 idling 和 long_task 是否都像这样完成:

async def main():
    task = asyncio.create_task(long_task())
    task2 = asyncio.create_task(do_while_idle())
    done, _ = await asyncio.wait({task, task2})

    if task and task2 in done:
        print(task.result(), task2.result())

第一个代码 sn-p 会给你你想要的结果:

IDLE
IDLE
IDLE
DONE !

【讨论】:

  • 感谢您的宝贵时间。但这不是我所需要的。无论“long_task”运行多长时间,我都需要 do_while_idle() 每隔一秒返回/打印一次。您的代码 sn-p 之所以有效,是因为您在两个 coro 中都硬编码了“3”。
  • @daolf 您可以将for _ in range(3) 替换为while True,它应该也能正常工作。
  • 我认为不会因为 asyncio.wait 等待所有任务完成。
  • @daolf 是的,您可以将其替换为 while True,因为在第一个代码 sn-p 中,当 long_task 完成时,正在取消 task2
  • @daolf 好点。它可以通过使用return_when=FIRST_COMPLETED 来修复,但完全可以不用wait() 来表达。我已经把它写下来作为答案。
猜你喜欢
  • 1970-01-01
  • 2022-01-18
  • 1970-01-01
  • 1970-01-01
  • 2019-02-21
  • 1970-01-01
  • 2019-12-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多