asyncio.wait([asyncio.sleep(5)])和asyncio.sleep(5)之间的区别 [英] Difference between `asyncio.wait([asyncio.sleep(5)])` and `asyncio.sleep(5)`

查看:128
本文介绍了asyncio.wait([asyncio.sleep(5)])和asyncio.sleep(5)之间的区别的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有人可以解释一下为什么 coro2 精加工和 coro1 精加工之间有5秒的延迟吗?

Could somebody please explain why there is a 5 second delay between coro2 finishing and coro1 finishing?

此外,如果我将 asyncio.wait([asyncio.sleep(5)])替换为 asyncio.sleep(5),为什么没有这样的延迟?

Also, why is there no such delay if I replace asyncio.wait([asyncio.sleep(5)]) with asyncio.sleep(5)?

async def coro1():
    logger.info("coro1 start")
    await asyncio.wait([asyncio.sleep(5)])
    logger.info("coro1 finish")

async def coro2():
    logger.info("coro2 start")
    time.sleep(10)
    logger.info("coro2 finish")

async def main():
    await asyncio.gather(coro1(), coro2())

loop = asyncio.get_event_loop()
loop.run_until_complete(main())

2020-05-25 12:44:56 coro1 start
2020-05-25 12:44:56 coro2 start
2020-05-25 12:45:06 coro2 finish
2020-05-25 12:45:11 coro1 finish

推荐答案

TLDR:请勿在协程中使用诸如 time.sleep 之类的阻塞调用.使用 asyncio.sleep 异步暂停,或使用

TLDR: Do not use blocking calls such as time.sleep in a coroutine. Use asyncio.sleep to asynchronously pause, or use an event loop executor if blocking code must be run.

使用 asyncio.wait([thing])添加一个间接级别,在新的Future/Task中执行 thing .当裸 await asyncio.sleep(5) coro1 期间执行睡眠时,包装的 await asyncio.wait([asyncio.sleep(5)])在所有其他当前计划的协程中执行 睡眠.

Using asyncio.wait([thing]) adds a level of indirection, executing thing in a new Future/Task. While a bare await asyncio.sleep(5) executes the sleep during coro1, the wrapped await asyncio.wait([asyncio.sleep(5)]) executes the sleep after all other currently scheduled coroutines.

async def coro1():
    logger.info("coro1 start")
    await asyncio.sleep(5)   # started immediately
    logger.info("coro1 finish")

async def coro1():
    logger.info("coro1 start")
    await asyncio.wait([     # started immediately
        asyncio.sleep(5)     # started in new task
    ])
    logger.info("coro1 finish")

由于 coro2 使用了阻塞的 time.sleep(10),因此它禁用了事件循环和所有其他协同程序.

Since coro2 uses the blocking time.sleep(10), it disables the event loop and all other coroutines.

async def coro2():
    logger.info("coro2 start")
    time.sleep(10)           # nothing happens for 10 seconds
    logger.info("coro2 finish")

这将阻止进一步的Futures的启动-包括来自 asyncio.wait 的新的Future-以及无法恢复-包括裸露的 asyncio.sleep(5)的未来.在前一种情况下,这意味着 asyncio.sleep time.sleep 完成后开始-因此需要 10 + 5 秒即可完成.在后一种情况下,这意味着 asyncio.sleep 已经开始,它只是无法在10秒内完成 -因此,将 max(10,5)秒完成.

This prevents further Futures from being started - including new future from asyncio.wait - and from being resumed - including the bare asyncio.sleep(5). In the former case, that means the asyncio.sleep starts after the time.sleep is done - therefore taking 10 + 5 seconds to complete. In the latter case, that means the asyncio.sleep has already started, it just cannot complete before the 10 seconds are up - therefore taking max(10, 5) seconds to complete.

始终使用 asyncio.sleep 来获取所需的持续时间.如果必须执行阻塞代码,请

Consistently use asyncio.sleep to get the desired durations. If blocking code must be executed, have it run via an executor.

async def coro1w():
    print("coro1w start", time.asctime())
    await asyncio.wait([asyncio.sleep(5)])
    print("coro1w finish", time.asctime())

async def coro1b():
    print("coro1b start", time.asctime())
    await asyncio.sleep(5)
    print("coro1b finish", time.asctime())

async def coro2a():
    print("coro2a start", time.asctime())
    await asyncio.sleep(10)            # asynchronous sleep
    print("coro2a finish", time.asctime())

async def coro2t():
    print("coro2t start", time.asctime())
    loop = asyncio.get_running_loop()  # threaded sleep
    await loop.run_in_executor(None, lambda: time.sleep(10))
    print("coro2t finish", time.asctime())

async def main():
    await asyncio.gather(coro1w(), coro1b(), coro2a(), coro2t())

asyncio.run(main())

这篇关于asyncio.wait([asyncio.sleep(5)])和asyncio.sleep(5)之间的区别的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆