python - 如何在 python 中提高睡眠/暂停时间的准确性?
问题描述
我进行了一个实验来比较 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库/技术也没关系,只要它更准确:)
解决方案
问题不仅在于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.timedelta
sleep_until
因此,如果您想获得微秒级的精度,那么您需要寻找性能更好的时间库datetime
。
推荐阅读
- java - 我如何知道从 Kotlin 调用 java 方法时是否应在调用站点检查可空参数?
- python - 如何拆分熊猫中的一组相关列?
- python - 使用 Pandas 根据日期和事件状态对数据进行排序
- selenium - 使用 selenium 驱动程序并行获取多个页面
- c# - WPF .NET Core 3.1 / .NET 5.0 中的 Catel.Fody - 未找到命名空间问题
- c++ - 将数组创建为具有 1000 万个元素的向量并分配不重复的随机数
- multiprocessing - 为什么在 Python3.8+ `multiprocessing` 中使用“fork”有效但使用“spawn”失败?
- java - Windows内存管理和java
- r - ggplot2 的 scale_fill_gradient2 中的动态中点
- c# - 使用继承策略将类型实例转换为不同类型的实例