如何在python中增加睡眠/暂停计时精度?

时间:2019-03-04 10:45:11

标签: python c++ python-3.x sleep system-clock

我进行了一项实验,以比较python和C ++中的睡眠/暂停计时准确性

实验摘要:

在1000000次迭代的循环中,每次迭代睡眠1微秒。

预期持续时间: 1.000000秒(对于100%准确的程序)

在python中:

import pause
import datetime

start = time.time()
dt = datetime.datetime.now()
for i in range(1000000):
    dt += datetime.timedelta(microseconds=1)
    pause.until(dt)
end = time.time()
print(end - start)

预期::1.000000秒,实际(近似值): 2.603796

在C ++中:

#include <iostream>
#include <chrono>
#include <thread>

using namespace std;

using usec = std::chrono::microseconds;
using datetime = chrono::_V2::steady_clock::time_point;
using clk = chrono::_V2::steady_clock;

int main()
{
    datetime dt;
    usec timedelta = static_cast<usec>(1);

    dt = clk::now();

    const auto start = dt;

    for(int i=0; i < 1000000; ++i) {
        dt += timedelta;
        this_thread::sleep_until(dt);
    }

    const auto end = clk::now();

    chrono::duration<double> elapsed_seconds = end - start;

    cout << elapsed_seconds.count();

    return 0;
}

预期::1.000000秒,实际(近似): 1.000040

很明显,C ++更加准确,但是我正在用python开发一个项目,需要提高准确性。有什么想法吗?

PS ,如果您建议另一个python库/技术,只要它更准确,就可以了:)

4 个答案:

答案 0 :(得分:1)

问题不仅在于python的睡眠计时器不正确,而且循环的每个部分都需要一些时间。

您的原始代码在我的系统上的运行时间为〜1.9528656005859375。

如果我只运行这段代码而没有任何睡眠:

for i in range(100000):
   dt += datetime.timedelta(microseconds=1)

那么该循环所需的时间已经是〜0.45999741554260254。

如果我只跑

for i in range(1000000):
   pause.milliseconds(0)

然后代码的运行时间为〜0.5583224296569824。

始终使用同一日期:

dt = datetime.datetime.now()
for i in range(1000000):
    pause.until(dt)

运行时间约为1.326077938079834

如果您对时间戳做同样的事情:

dt = datetime.datetime.now()
ts = dt.timestamp()
for i in range(1000000):
    pause.until(ts)

然后运行时更改为〜0.36722803115844727

如果将时间戳增加1微秒:

dt = datetime.datetime.now()
ts = dt.timestamp()
for i in range(1000000):
    ts += 0.000001
    pause.until(ts)

然后您将获得〜0.9536933898925781的运行时间

小于1的原因是由于浮点数不正确,在循环后添加print(ts-dt.timestamp())将显示〜0.95367431640625,因此暂停持续时间本身是正确的,但是ts += 0.000001会累积一个错误。

如果计算迭代次数,并将iterationCount/1000000添加到开始时间,您将获得最佳结果:

dt = datetime.datetime.now()
ts = dt.timestamp()
for i in range(1000000):
    pause.until(ts+i/1000000)

这将导致〜1.000023365020752

因此,在我的情况下,pause本身已经允许小于1微秒的精度。问题实际上出在datetimedatetime.timedelta都需要的sleep_until部分中。

因此,如果要具有微秒级的精度,则需要寻找性能比datetime更好的时库。

答案 1 :(得分:0)

import pause
import datetime
import time

start = time.time()
dt = datetime.datetime.now()

for i in range(1000000):
    dt += datetime.timedelta(microseconds=1)
    pause.until(1) 
end = time.time()
print(end - start)

输出:

1.0014092922210693

答案 2 :(得分:0)

暂停库说

  

精度应在0.001秒之内,但这取决于系统睡眠的精确度和其他性能因素。

如果将0.001乘以1000000,将得到较大的累积误差。

几个问题:

为什么需要睡觉?

最低要求的准确度是多少?

您要调用的操作的时间一致性如何?如果这些函数调用的差异超过0.001,则累积的错误将更多地归因于您正在执行的操作,而不是归因于暂停/睡眠。

答案 3 :(得分:-1)

休眠线程本质上是不确定的-一般而言,您不能真正地为线程sleeep谈论“精度”-也许仅在特定系统和平台的上下文中-太多了可能发挥作用的因素,例如多少个cpu核心等。

为说明这一点,我们进行了思想实验

假设您创建了许多个线程(至少1000个),并安排它们在相同的确切时间运行。您会期望什么“精度”?