3

我进行了一个实验来比较 python 和 C++ 中的睡眠/暂停时间准确性

实验总结:

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

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

在蟒蛇中:

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

4 回答 4

2

问题不仅在于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

如果您将时间戳增加一微秒:

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 微秒的精度。问题实际上出在和datetime都需要的部分。datetime.timedeltasleep_until

因此,如果您想获得微秒级的精度,那么您需要寻找性能更好的时间库datetime

于 2019-03-04T14:33:26.913 回答
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
于 2019-03-04T10:54:35.323 回答
0

暂停库说

精度应该在 0.001 秒以内,但是,这将取决于您的系统睡眠的精度和其他性能因素。

如果你将 0.001 乘以 1000000,你会得到一个很大的累积误差。

几个问题:

为什么需要睡觉?

要求的最低精度是多少?

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

于 2019-03-04T11:07:28.937 回答
0

让线程休眠本质上是不确定的——一般来说,你不能真正谈论线程休眠的“精度”——也许只能在特定系统和平台的上下文中——有太多的因素可能会起作用,例如如何许多cpu核心等。

为了说明这一点,一个思想实验

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

于 2019-03-04T13:39:58.903 回答