gpt4 book ai didi

python - `asyncio.sleep(delay)` 是否保证至少休眠 `delay` 秒?

转载 作者:行者123 更新时间:2023-12-05 00:54:44 31 4
gpt4 key购买 nike

asyncio.sleep() 的阻塞表亲,time.sleep() , 不能保证它会在请求的时间内休眠。

The actual suspension time may be less than that requested because any caught signal will terminate the sleep() following execution of that signal’s catching routine.

asyncio.sleep()documentation没有提到类似的限制。

asyncio.sleep() 是否能够对 sleep 时间做出更强有力的保证?

最佳答案

我不会告诉asyncio 保证是什么,但是根据实现它遵循asyncio.sleep()(基本上,call_later()) 休眠指定的时间间隔,但至少与实现中使用的系统时钟分辨率相同

让我们弄清楚。首先,asyncio 使用单调时钟,有不同的分辨率on different platforms (Python 和 OS 分辨率)。例如,对于 Windows,这相当于 15ms

在保证方面,注意对函数BaseEventLoop.time的注释:

    def time(self):
"""Return the time according to the event loop's clock.
This is a float expressed in seconds since an epoch, but the
epoch, precision, accuracy and drift are unspecified and may
differ per event loop.
"""
return time.monotonic()

现在我们来看看asyncio事件循环源码code负责启动计划的计时器:

        # Handle 'later' callbacks that are ready.
end_time = self.time() + self._clock_resolution
while self._scheduled:
handle = self._scheduled[0]
if handle._when >= end_time:
break
handle = heapq.heappop(self._scheduled)
handle._scheduled = False
self._ready.append(handle)

end_time = self.time() + self._clock_resolution 行显示回调可能比计划的更早触发,但在时钟分辨率范围内。 Yuri Selivanov 明确说明了这一点here :

As I see it, currently we peek into the future time. Why don't we do

       end_time = self.time() - self._clock_resolution

to guarantee that timeouts will always be triggered after the requested time, not before? I don't see how the performance can become worse if we do this.

真的,让我们运行下一个程序(Windows 10 上的 Python 3.8):

import asyncio 
import time

async def main():
print("Timer resolution", time.get_clock_info('monotonic').resolution)
while True:
asyncio.create_task(asyncio.sleep(1))

t0 = time.monotonic()
await asyncio.sleep(0.1)
t1 = time.monotonic()

print(t1 - t0)
asyncio.run(main())

我们看到上述行为:

Timer resolution 0.015625
0.09299999987706542
0.0940000000409782
0.0940000000409782
0.10900000017136335
...

但是在正文的开头,我说至少时钟分辨率,因为asyncio工作在协同多任务的条件下,如果有贪心协程(或许多不那么贪婪的),不经常控制事件循环,我们有以下图片:

import asyncio 
import time

async def calc():
while True:
k = 0
for i in range(1*10**6):
k += i
await asyncio.sleep(0.1) # yield to event loop


async def main():
asyncio.create_task(calc()) # start greedy coroutine
print("Timer resolution", time.get_clock_info('monotonic').resolution)
while True:
asyncio.create_task(asyncio.sleep(1))

t0 = time.monotonic()
await asyncio.sleep(0.1)
t1 = time.monotonic()

print(t1 - t0)
asyncio.run(main())

不出所料,情况正朝着延迟增加的方向发生变化:

0.17200000025331974
0.1559999999590218
0.14100000029429793
0.2190000000409782

关于python - `asyncio.sleep(delay)` 是否保证至少休眠 `delay` 秒?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65715878/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com