python的time.sleep()有多准确?

Cla*_*diu 82 python time sleep

我可以给它浮点数,比如

time.sleep(0.5)
Run Code Online (Sandbox Code Playgroud)

但它有多准确?如果我给它

time.sleep(0.05)
Run Code Online (Sandbox Code Playgroud)

它真的睡了大约50毫秒?

Jos*_*see 70

time.sleep函数的准确性取决于您的基础操作系统的睡眠准确性.对于非实时操作系统,如股票Windows,您可以睡觉的最小间隔大约是10-13ms.我已经看到在超过最小10-13ms时的几毫秒内准确睡眠.

更新:如下面引用的文档中提到的,在循环中进行睡眠是很常见的,如果它提前唤醒你,它将确保重新进入睡眠状态.

我还要提一下,如果您正在运行Ubuntu,您可以通过安装rt内核包(至少在Ubuntu 10.04 LTS中)尝试伪实时内核(使用RT_PREEMPT补丁集).

编辑:更正非实时Linux内核的最小睡眠间隔更接近1毫秒然后10毫秒但它以非确定性方式变化.

  • 实际上,Linux内核在很长一段时间内都违反了较高的滴答速率,因此"最小"睡眠时间比10ms更接近1ms.它无法保证 - 即使没有CPU争用,其他系统活动也可能使内核无法在您希望的情况下尽快安排您的进程.我认为这就是实时内核试图修复的内容.但是,除非你真的需要实时行为,否则只需使用高刻度率(内核HZ设置)就可以在Linux中获得无保证但高分辨率的睡眠,而无需使用任何特殊功能. (8认同)
  • 此外,准确性不仅取决于操作系统,而且操作系统在Windows和Linux上都在做什么,如果他们忙于从文档中做一些更重要的"sleep()",那么暂停时间可能比任意数量的请求更长因为系统中其他活动的安排". (2认同)

Wil*_*ert 51

人们对操作系统和内核之间的差异非常正确,但我没有看到Ubuntu中的任何粒度,我在MS7中看到了1 ms的粒度.建议不同的time.sleep实现,而不仅仅是不同的滴答速率.仔细检查表明Ubuntu中的粒度为1μs,但这是由于我用于测量精度的time.time函数. Linux和Windows在Python中的典型time.sleep行为

  • 有趣的是Linux如何选择总是睡眠时间比请求的时间长,而微软选择了相反的方法. (6认同)
  • @jleahy - linux方法对我有意义:睡眠实际上是执行优先级的释放一段时间之后你再次提交自己的调度程序的意愿(可能会或可能不会安排你立即执行) . (2认同)
  • 你是怎么得到结果的?您能提供源代码吗?该图看起来像是使用不同的计时器来测量时间和睡眠的人工产物(原则上,您甚至可以[使用计时器之间的漂移作为随机性来源](http://stackoverflow.com/a/28721505/ 4279))。 (2认同)
  • @JF Sebastian - 我使用的函数在 https://www.socsci.ru.nl/wilberth/computer/sleepAccuracy.html 。第三张图显示的效果与您所看到的相似,但仅为 1‰。 (2认同)

Ste*_*202 26

文档:

在另一方面,精度 time()sleep()比其的Unix等效物更好:次被表示为浮点数, time()返回可用最准确的时间(使用的Unix gettimeofday 如果有的话),以及sleep()将接受具有非零分数的时间(Unix的select使用在可能的情况下实现这一点.

更具体 WRT sleep():

暂停执行给定的秒数.参数可以是浮点数,以指示更精确的睡眠时间.实际的暂停时间可能小于请求的时间,因为任何捕获的信号都将终止该sleep()信号捕获程序的后续执行.此外,由于系统中其他活动的安排,暂停时间可能比任意量请求的时间.

  • 任何人都可以解释“因为任何捕获的信号都会在执行该信号的捕获例程后终止 sleep() ”吗?它指的是哪些信号?谢谢! (2认同)
  • 信号就像操作系统管理的通知(http://en.wikipedia.org/wiki/Unix_signal),这意味着如果操作系统捕获到信号,则 sleep() 在处理该信号后完成。 (2认同)

Tim*_*nie 20

这是我对Wilbert的回答的跟进:对于Mac OS X Yosemite来说也是如此,因为它还没有被提及.Mac OS X Yosemite的睡眠行为

看起来很多时候它的睡眠时间大约是你要求的时间的1.25倍,有时会在你要求的时间内睡1到1.25倍.它几乎从不(1000个样本中的两个)睡眠时间远远超过您要求的1.25倍.

另外(未明确显示)1.25关系似乎保持相当好,直到你低于约0.2毫秒,之后它开始变得有点模糊.此外,在请求的时间超过20毫秒后,实际时间似乎比您请求的时间长约5毫秒.

同样,它似乎是sleep()在OS X中完全不同于Windows中的实现或者任何Linux内核Wilbert正在使用的实现.

  • 我在我的机器上试过[它](http://pastebin.com/5cmMaJjb).[结果类似于@ Wilbert的回答](http://i.stack.imgur.com/l8L9M.png). (2认同)

Lar*_*ars 19

如果您需要更精确或更短的睡眠时间,请考虑自己制作:

import time

def sleep(duration, get_now=time.perf_counter):
    now = get_now()
    end = now + duration
    while now < end:
        now = get_now()
Run Code Online (Sandbox Code Playgroud)

  • @Jodo,因为这个函数会导致 100% 的 CPU 使用率(这对于“睡眠”的许多用例来说显然是不切实际的)。减少此函数 CPU 使用率的唯一方法是添加对... `sleep` 的调用:) (4认同)

Ant*_*sma 16

你为什么不知道:

from datetime import datetime
import time

def check_sleep(amount):
    start = datetime.now()
    time.sleep(amount)
    end = datetime.now()
    delta = end-start
    return delta.seconds + delta.microseconds/1000000.

error = sum(abs(check_sleep(0.050)-0.050) for i in xrange(100))*10
print "Average error is %0.2fms" % error
Run Code Online (Sandbox Code Playgroud)

为了记录,我的HTPC上的错误大约为0.1ms,而我的笔记本电脑上的这两台Linux机器上的错误都是2ms.

  • 经验测试会给你一个非常狭隘的观点.有许多内核,操作系统和内核配置会影响这一点.较旧的Linux内核默认为较低的滴答速率,从而产生更大的粒度.在Unix实现中,睡眠期间的外部信号将随时取消,其他实现可能会有类似的中断. (10认同)
  • 当然,经验观察是不可转移的.除了操作系统和内核之外,还有许多影响此问题的瞬态问题.如果需要硬实时保证,则需要考虑从硬件开始的整个系统设计.我刚刚发现结果相关,考虑到10ms是最小精度的陈述.我不在Windows世界的家中,但是大多数Linux发行版已经运行了一段时间无内核.随着多核现在普遍存在,它很可能会被安排在非常接近超时的时间. (6认同)

mil*_*bar 8

time.sleep方法在即将发布的 Python (3.11) 版本中已进行了大量重构。现在,Windows 和 Unix 平台上都可以达到类似的精度,并且默认情况下始终使用最高的精度。以下是新文档的相关部分:

在 Windows 上,如果 secs 为零,则线程会将其剩余时间片让给任何其他准备运行的线程。如果没有其他线程准备运行,该函数立即返回,并且该线程继续执行。在 Windows 8.1 及更高版本上,该实现使用高分辨率计时器,提供 100 纳秒的分辨率。如果 secs 为零,则使用 Sleep(0)。

Unix 实现:

  • 如果可用,请使用clock_nanosleep()(分辨率:1纳秒);
  • 或者使用 nanosleep() (如果可用)(分辨率:1 纳秒);
  • 或者使用 select() (分辨率:1 微秒)。

因此,从 python 3.11 开始,在大多数平台上只需调用time.sleep就可以了,这是一个好消息!最好对这个新实现进行类似于 @wilbert 的跨平台基准测试。


use*_*405 5

一个小小的修正,一些人提到睡眠可以通过信号提前结束。在3.6 文档中它说,

在 3.5 版更改:即使睡眠被信号中断,该函数现在也至少睡眠几秒钟,除非信号处理程序引发异常(有关基本原理,请参阅PEP 475)。