asyncio.sleep 如何不阻塞线程? [英] How asyncio.sleep isn't blocking thread?

查看:114
本文介绍了asyncio.sleep 如何不阻塞线程?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一遍又一遍地阅读Luciano Ramalho"的Fluent Python",但我无法理解 asyncio.sleep 在 asyncio 中的行为.

I'm reading 'Fluent Python' by 'Luciano Ramalho' over and over, but I couldn't understand asyncio.sleep's behavior inside asyncio.

书中有一部分说:

切勿在 asyncio 协程中使用 time.sleep,除非您想阻塞主线程,否则会冻结事件循环,也可能冻结整个应用程序.(...) 它应该从 asyncio.sleep(DELAY) 产生.

Never use time.sleep in asyncio coroutines unless you want to block the main thread, therefore freezing the event loop and probably the whole application as well. (...) it should yield from asyncio.sleep(DELAY).

另一方面:

Python 标准库中的每个阻塞 I/O 函数都会释放 GIL (...) time.sleep() 函数也释放 GIL.

Every Blocking I/O function in the Python standard library releases the GIL (...) The time.sleep() function also releases the GIL.

由于 time.sleep() 释放 GIL 代码,其他线程可以运行,但会阻塞当前线程.由于 asyncio 是单线程的,我理解 time.sleep 会阻塞 asyncio 循环.

As time.sleep() releases GIL codes on other thread can run, but blocks current thread. Since asyncio is single-threaded, I understand that time.sleep blocks asyncio loop.

但是,asyncio.sleep() 如何不阻塞线程?是否可以不延迟事件循环并同时等待?

But, how asyncio.sleep() isn't blocking thread? Is it possible to not delay event loop and wait at the same time?

推荐答案

asyncio.sleep 函数很简单 注册在 x 内调用的 future,而 time.sleep ="https://docs.python.org/3/library/time.html#time.sleep" rel="nofollow noreferrer">暂停执行 x.

The function asyncio.sleep simply registers a future to be called in x seconds while time.sleep suspends the execution for x seconds.

您可以用这个小例子测试两者的行为,看看 asyncio.sleep(1) 实际上没有给您任何关于它将休眠"多长时间的任何线索.因为这不是它真正的作用:

You can test how both behave with this small example and see how asyncio.sleep(1) doesn't actually give you any clue on how long it will "sleep" because it's not what it really does:

import asyncio 
import time
from datetime import datetime


async def sleep_demo():
    print("sleep_demo start: ", datetime.now().time())
    await asyncio.sleep(1)
    print("sleep_demo end: ", datetime.now().time())
    

async def I_block_everyone():
    print("I_block_everyone start: ", datetime.now().time())
    time.sleep(3)
    print("I_block_everyone end: ", datetime.now().time())
    
    
asyncio.gather(*[sleep_demo(), I_block_everyone()])

打印:

sleep_demo start:  04:46:55.902913
I_block_everyone start:  04:46:55.903119
I_block_everyone end:  04:46:58.905383
sleep_demo end:  04:46:58.906038

阻塞调用 time.sleep 阻止事件循环调度恢复 sleep_demo 的未来.最终,它在大约 3 秒后才重新获得控制权.

The blocking call time.sleep prevent the event loop from scheduling the future that resumes sleep_demo. In the end, it gains control back only after approximately 3 seconds.

现在关于time.sleep() 函数也释放 GIL.",这并不矛盾,因为它只会允许另一个线程执行(但当前线程将保留等待 x 秒).两者看起来有点相似,在一种情况下,释放 GIL 为另一个线程腾出空间,在 asyncio.sleep 中,事件循环获得控制权以安排另一个任务.

Now concerning "The time.sleep() function also releases the GIL.", this is not a contradiction as it will only allow another thread to execute (but the current thread will remain pending for x seconds). Somewhat both look a bit similar, in one case the GIL is released to make room for another thread, in asyncio.sleep, the event loop gains control back to schedule another task.

这篇关于asyncio.sleep 如何不阻塞线程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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