我想在 Perl 中以纳秒为单位获得系统时间。我尝试Time::HiRes
了模块,它只支持微秒。
5 回答
Time::HiRes模块最多支持微秒。正如@MarcoS 在当今常见的硬件中所回答的那样,使用软件计算的纳秒精度是无稽之谈。
随后的两个调用,获取当前微秒并在之后打印
perl -MTime::HiRes=time -E '$t1=time; $t2=time; printf "%.6f\n", $_ for($t1, $t2)'
结果(在我的系统上)
1411630025.846065
1411630025.846069
例如,只获得当前时间两次,并且没有任何成本 3-4 微秒。
如果您想要一些“纳秒数”,只需以 9digit 精度打印时间,例如:
perl -MTime::HiRes=time -E '$t1=time;$t2=time; printf "%.9f\n", $_ for($t1, $t2)'
你会得到:
1411630910.582282066
1411630910.582283974
相当纳秒的时间;)
无论如何,您可以以合理的纳秒精度入睡。从文档
纳秒睡眠($纳秒)
休眠指定的纳秒数(1e9 秒)。返回实际睡眠的纳秒数(精确到微秒,最接近的一千)。
...
不要期望 nanosleep() 精确到一纳秒。甚至达到一千纳秒的精度也很好。
当然,时间分辨率取决于硬件时钟频率。
例如,AMD 5200 的时钟为 2.6Ghz,其间隔为 0.4ns。使用 RDTSCP 的 gettimeofday 成本是 221 个周期:最多等于 88ns。Perl 例程的最低成本将是数百倍......
所以,最终的答案是:
在今天的硬件上,忘记纳秒。使用 Perl 和任何高级语言...您可以仅使用汇编程序就可以接近,但忘记计算单个纳秒,使用软件...
Perl 使用 Time::HiRes获取时间
c:\Code>perl -MDateTime::HiRes -E "while (1) {say DateTime::HiRes->now()->strftime('%F %T.%N');}"
或者
use Time::HiRes qw(time);
use POSIX qw(strftime);
my $t = time;
my $date = strftime "%F %T.%N", localtime $t;
$date .= sprintf ".%03d", ($t-int($t))*1000; # without rounding
print $date, "\n";
“忘记纳秒”的人都错了:普通机器上的 perl 现在通常在后续调用中返回相同的微秒,因此虽然可能(还)无法实现实际的纳秒分辨率,但您现在绝对需要纳秒,因为微秒太粗糙了。
上面的答案是错误的——从浮点数的不精确中捏造更多的数字并不能提供更高的精度:-
perl -MTime::HiRes=time -E 'while(1){my $now=sprintf("%.9f",time); die if($now==$last);$last=$now}'
该代码执行此操作:
Died at -e line 1.
基本问题是 Perl 的 Time::HiRes 使用普通浮点值来表示时间戳,通常实现为原生 C double
,在许多平台上是 64 位 IEEE 浮点数,尾数为 53 位。
这意味着时间戳记录的分辨率会随着它们与 1970 年的距离而变化:
大致日期范围 | 解析度 | ||
---|---|---|---|
1969 年 11 月 13 日 ~ 1970 年 2 月 18 日 | 小于 0.93ns | 可用纳秒分辨率 | |
1969 年 9 月 25 日 ~ 1970 年 4 月 8 日 | 1.86ns | ||
1969 年 6 月 20 日 ~ 1970 年 7 月 14 日 | 3.73ns | ||
1968 年 12 月 8 日 ~ 1971 年 1 月 24 日 | 7.45ns | ||
1967 年 11 月 16 日 ~ 1972 年 2 月 16 日 | 14.9ns | ||
1961 年 7 月 ~ 1978 年 6 月 | 29.8ns | ||
1978~1986 & 1953~1961 | 59.6ns | ||
1987~2003 & 1936~1952 | 0.119µs | ||
►</td> | 2004~2037 & 1902~1935 | 0.238µs | ◄</td> |
2038~2105 & 1834~1901 | 0.477µs | ||
2106~2242 & 1698~1833 | 0.954µs | ||
1697 年之前或 2107 年之后 | 比微秒分辨率差 |