意外的 time.sleep() 行为

Unexpected time.sleep() behaviour

最近,在创建一个最后等待时间很短的循环时,我 运行 在快速连续使用时出现 time.sleep() 的意外行为。

我使用这段代码进一步研究了我的问题

import time
import statistics

def average_wait(func):
    waits=[]
    loops=0

    while loops<1000:
            start=time.time()
            func(1/1000)
            waits.append(time.time()-start)
            loops+=1
    print(waits)
    print("Average wait for 0.001: {}".format(statistics.mean(waits)))

average_wait(time.sleep)

这个函数通常 returns 大约 0.0013,这比只调用 time.sleep() 一次准确很多倍,通过查看 waits 列表进一步检查这个问题,我发现 time.sleep() 实际睡眠的时间要么几乎完全正确,要么几乎恰好是时间的两倍。

这是来自 waits 的示例: [0.0010008811950683594, 0.0020041465759277344, 0.0009999275207519531, 0.0019621849060058594, 0.0010418891906738281]

这种行为有什么原因吗?可以采取什么措施来避免这种情况?

来自time.time() documentation

Note that even though the time is always returned as a floating point number, not all systems provide time with a better precision than 1 second.

精度取决于平台。此外,它会产生挂钟时间,并且您的进程从来不是现代 OS 上唯一的进程 运行,其他进程 有时间处理和因此,您会在自己的流程中看到时间上的变化。

该模块提供不同的时钟,精度更高,有些是针对每个进程的。请参阅 time.get_clock_info() function to see what precision they offer. Note time.process_time() 提供每个进程的时间但不包括睡眠时间。

接下来,time.sleep() 也不会在确切的时间跨度内睡觉;再次来自 relevant documentation:

[T]he suspension time may be longer than requested by an arbitrary amount because of the scheduling of other activity in the system.

它也受制于 OS 调度。

这些影响加起来很容易达到您在实验中看到的毫秒时间变化。所以这不是睡眠时间的翻倍;即使您为 time.sleep() 使用不同的值,您仍然会看到与请求时间的类似偏差。