为什么这些时间戳与Perl Time :: HiRes无关?

ajw*_*ood 5 unix perl timestamp ext4

我看到Perl Time::HiRes模块报告的时间戳有些奇怪的行为.

我有一个获得三个时间戳的脚本:

  1. 获取时间戳 Time::HiRes::time
  2. 创建一个新文件,并获取其修改时间 Time::HiRes::stat
  3. 获取时间戳 Time::HiRes::time

我希望订购时间戳1 < 2 < 3,但情况并非总是如此; 通常(但不总是),stat在2.中报告的时间是 1 之前的时间戳之前.

我在Ext4文件系统上.这是一个实验:

use Time::HiRes qw/ time stat /;

while( 1 ){
    # t0
    my $t0 = time;

    # Create a file
    my $f = '/tmp/dummy.test';
    open(my $fh, '>', $f) || die;
    print $fh "hi\n";
    close($fh) || die;

    # FS: file modification time, according to the filestystem
    my $fs = (stat($f))[9];

    # t1
    my $t1 = time;

    ## Report how the timestamps relate to each other
    # A. All good
    if( $t0 < $fs && $fs < $t1 ){
       print "$t1,0\n";
    }
    # B. FS before t0
    elsif( $t0 > $fs && $fs < $t1 ){
       print "$t1,1\n";
    }
    # C. FS after t1
    elsif( $t0 < $fs && $fs > $t1 ){
       print "$t1,2\n";
    }
    # D. this should never happen (t0 and t1 probably can't flip)
    elsif( $t0 > $fs && $fs > $t1 ){
       print "$t1,3\n";
    }
}
Run Code Online (Sandbox Code Playgroud)

以下是让上述循环运行几秒钟的结果.底部的蓝点是"正确"行为的事件.通常情况下,我得到条件B,其中修改时间stat第一个时间戳之前.

在此输入图像描述

有什么可以解释这种行为?

更新:这是第2000次迭代的时间戳滞后图:

在此输入图像描述

Dhr*_*hak 5

这可能是因为这里的doc中提到的两个时间戳的精度不同:

作为stat或lstat,但访问/修改/更改文件时间戳以亚秒级分辨率,如果操作系统和文件系统都支持这样的时间戳.要覆盖标准stat():

use Time::HiRes qw(stat);
Run Code Online (Sandbox Code Playgroud)

测试&Time :: HiRes :: d_hires_stat的值以确定操作系统是否支持亚秒文件时间戳:大于零的值表示是.遗憾的是,没有简单的方法可以确定文件系统是否支持这样的时间戳.UNIX文件系统经常这样做; NTFS确实; FAT没有(FAT时间戳粒度为2秒).

&Time :: HiRes :: d_hires_stat的零返回值意味着Time :: HiRes :: stat是CORE :: stat()的无操作直通(对于lstat也是如此),因此时间戳将保持整数.如果文件系统不执行亚秒级时间戳,即使&Time :: HiRes :: d_hires_stat非零,也会发生同样的情况.

在任何情况下都不要指望纳秒分辨率,甚至是微秒分辨率.另请注意,修改/访问时间戳可能具有不同的分辨率,并且无需同步,例如,如果操作是

write
stat # t1
read
stat # t2
Run Code Online (Sandbox Code Playgroud)

来自t2的访问时间标记不必大于来自t1的修改时间标记:它可以等于或小于.