內容

名稱

Time::HiRes - 高解析度警報、休眠、gettimeofday、區間計時器

語法

use Time::HiRes qw( usleep ualarm gettimeofday tv_interval nanosleep
                    clock_gettime clock_getres clock_nanosleep clock
                    stat lstat utime);

usleep ($microseconds);
nanosleep ($nanoseconds);

ualarm ($microseconds);
ualarm ($microseconds, $interval_microseconds);

$t0 = [gettimeofday];
($seconds, $microseconds) = gettimeofday;

$elapsed = tv_interval ( $t0, [$seconds, $microseconds]);
$elapsed = tv_interval ( $t0, [gettimeofday]);
$elapsed = tv_interval ( $t0 );

use Time::HiRes qw ( time alarm sleep );

$now_fractions = time;
sleep ($floating_seconds);
alarm ($floating_seconds);
alarm ($floating_seconds, $floating_interval);

use Time::HiRes qw( setitimer getitimer );

setitimer ($which, $floating_seconds, $floating_interval );
getitimer ($which);

use Time::HiRes qw( clock_gettime clock_getres clock_nanosleep
                    ITIMER_REAL ITIMER_VIRTUAL ITIMER_PROF
                    ITIMER_REALPROF );

$realtime   = clock_gettime(CLOCK_REALTIME);
$resolution = clock_getres(CLOCK_REALTIME);

clock_nanosleep(CLOCK_REALTIME, 1.5e9);
clock_nanosleep(CLOCK_REALTIME, time()*1e9 + 10e9, TIMER_ABSTIME);

my $ticktock = clock();

use Time::HiRes qw( stat lstat );

my @stat = stat("file");
my @stat = stat(FH);
my @stat = lstat("file");

use Time::HiRes qw( utime );
utime $floating_seconds, $floating_seconds, file...;

說明

Time::HiRes 模組實作 Perl 介面,用於 usleepnanosleepualarmgettimeofdaysetitimer/getitimer 系統呼叫,換句話說,就是高解析度時間和計時器。請參閱下方的 "範例" 區段和測試腳本,以了解使用方式;請參閱系統文件,以了解底層 nanosleepusleepualarmgettimeofdaysetitimer/getitimer 呼叫的說明。

如果您的系統缺少 gettimeofday() 或其模擬,則您不會取得 gettimeofday()tv_interval() 的單一引數形式。如果您的系統缺少 nanosleep()usleep()select()poll,則您不會取得 Time::HiRes::usleep()Time::HiRes::nanosleep()Time::HiRes::sleep()。如果您的系統缺少 ualarm()setitimer(),則您不會取得 Time::HiRes::ualarm()Time::HiRes::alarm()

如果您嘗試在 use 陳述式中匯入未實作的函數,它會在編譯時失敗。

如果您的次秒睡眠是以 nanosleep() 而不是 usleep() 進行實作,您可以將次秒睡眠與訊號混合,因為 nanosleep() 不使用訊號。然而,這並非可移植的,您應先檢查 &Time::HiRes::d_nanosleep 的真值,以查看您是否有 nanosleep,然後仔細閱讀您的 nanosleep() C API 文件,了解任何特殊情況。

如果您將 nanosleep 用於除了將睡眠與訊號混合之外的其他用途,請考慮 Perl 是否是您應該用於需要奈秒精度的工作的工具。

請記住,除非您在 硬即時 系統上工作,否則任何時鐘和計時器都不會精確,特別是如果您在搶先式多使用者系統中工作。了解 時鐘時間 與處理時間之間的差異(在類 UNIX 系統中,使用者系統 時間的總和)。任何嘗試睡眠 X 秒的行為最終很可能會睡眠 超過該時間,但如果您最終睡眠的時間略 少於該時間,也請不要感到驚訝。

下列函式可以從此模組匯入。預設不會匯出任何函式。

gettimeofday ()

在陣列內容中傳回一個包含自紀元以來秒數和微秒數的二元素陣列。在純量內容中傳回浮點秒數,例如 Time::HiRes::time()(見下文)。

usleep ( $useconds )

睡眠指定的微秒數(百萬分之一秒)。傳回實際睡眠的微秒數。可以睡眠超過一秒,這與 usleep 系統呼叫不同。也可以睡眠零秒,這通常會像 執行緒讓步 一樣運作。另請參閱 Time::HiRes::sleep()clock_nanosleep()

請勿期望 usleep() 精確到一微秒。

nanosleep ( $nanoseconds )

睡眠指定的奈秒數(十億分之一秒)。傳回實際睡眠的奈秒數(僅精確到微秒,最接近一千個奈秒)。可以睡眠超過一秒。也可以睡眠零秒,這通常會像 執行緒讓步 一樣運作。另請參閱 Time::HiRes::sleep()Time::HiRes::usleep()clock_nanosleep()

請勿期望 nanosleep() 精確到一奈秒。即使獲得一千奈秒的精確度也很不錯了。

ualarm ( $useconds [, $interval_useconds ] )

發出 ualarm 呼叫;$interval_useconds 是選用的,如果未指定,將為零,導致類似 alarm 的行為。

以微秒為單位傳回警報中的剩餘時間,或在發生錯誤時傳回 undef

ualarm(0) 將取消未完成的 ualarm()。

請注意,警報和睡眠之間的互動未指定。

tv_interval

tv_interval ( $ref_to_gettimeofday [, $ref_to_later_gettimeofday] )

傳回兩個時間之間的浮動秒數,應由 gettimeofday() 傳回。如果省略第二個參數,則使用目前時間。

time ()

傳回自紀元以來的浮動秒數。可以匯入此函式,導致直接替換核心 Perl 提供的 time;請參閱下方的 "範例"

注意 1:此較高解析度計時器可以傳回小於或大於核心 time() 的值,具體取決於您的平台是向上、向下或四捨五入到最近一秒以取得核心 time(),但自然地,差異永遠不應超過半秒。如果您的系統中可用,請參閱 "clock_getres"

注意 2:自 2001 年 9 月 9 日星期日格林威治標準時間上午 01:46:40 以來,當紀元以來的 time() 秒數滾動到 1_000_000_000 時,Perl 的預設浮點格式和紀元以來的秒數串謀產生一個明顯的錯誤:如果您列印 Time::HiRes::time() 的值,您似乎只會得到五個小數,而不是承諾的六個(微秒)。不用擔心,微秒就在那裡(假設您的平台首先支援此類顆粒度)。正在發生的事情是 Perl 的預設浮點格式只輸出 15 個數字。在本例中,表示小數點前有十個數字,小數點後有五個數字。若要查看微秒,您可以使用 printf/sprintf 搭配 "%.6f",或在清單內容中使用 gettimeofday() 函式,它會將秒數和微秒作為兩個獨立的值提供給您。

sleep ( $floating_seconds )

睡眠指定秒數。傳回實際睡眠的秒數(浮點值)。可以匯入此函式,導致直接替換 perl 提供的 sleep;請參閱下方的 "範例"

請注意,警報和睡眠之間的互動未指定。

alarm ( $floating_seconds [, $interval_floating_seconds ] )

在指定秒數後發送 SIGALRM 訊號。如果可用,則使用 setitimer() 實作,否則使用 ualarm()$interval_floating_seconds 參數是選用的,如果未指定,將為零,導致類似 alarm() 的行為。可以匯入此函式,導致直接替換 perl 提供的 alarm;請參閱下方的 "範例"

傳回鬧鐘剩餘時間(以秒為單位),或在發生錯誤時傳回 undef

註 1:在某些作業系統和 Perl 版本組合中,SIGALRM 會重新啟動 select(),而不是中斷它。這表示 alarm() 後接 select() 可能會花費 alarm()select() 指定時間的總和,而不僅僅是 alarm() 的時間。

請注意,警報和睡眠之間的互動未指定。

setitimer ( $which, $floating_seconds [, $interval_floating_seconds ] )

啟動間隔計時器:在一段時間後,會收到一個訊號 ($which),而且可能會在特定間隔收到更多訊號。若要停用「計時器」,請使用零的 $floating_seconds。如果 $interval_floating_seconds 設為零(或未指定),則計時器會在傳送下一個訊號停用。

使用間隔計時器可能會干擾 alarm()sleep()usleep()。標準說法是「互動未指定」,這表示任何事都可能發生:它可能會運作,也可能不會。

在純量內容中,會傳回計時器中剩餘的時間。

在清單內容中,會傳回剩餘時間和間隔。

通常有三個或四個間隔計時器(訊號)可用:$which 可以是 ITIMER_REALITIMER_VIRTUALITIMER_PROFITIMER_REALPROF。請注意,哪些可用取決於:真正的 UNIX 平台通常有前三個,但只有 Solaris 似乎有 ITIMER_REALPROF(用於分析多執行緒程式)。很不幸地,Win32 沒有間隔計時器。

ITIMER_REAL 會產生類似 alarm() 的行為。時間以實際時間計算;也就是說,時鐘時間。當計時器到期時,會傳送 SIGALRM

ITIMER_VIRTUAL 以(處理)虛擬時間計算時間;也就是說,僅在處理執行時。在多處理器/使用者/CPU 系統中,這可能會多於或少於實際時間或時鐘時間。(此時間也稱為使用者時間。)當計時器到期時,會傳送 SIGVTALRM

ITIMER_PROF 在處理虛擬時間或作業系統代表處理執行(例如 I/O)時計算時間。(此時間也稱為系統時間。)(使用者時間和系統時間的總和稱為CPU 時間。)當計時器到期時,會傳送 SIGPROFSIGPROF 可以中斷系統呼叫。

多執行緒程式的間隔計時器語意取決於系統,而且有些系統可能會支援額外的間隔計時器。例如,未指定哪個執行緒會收到訊號。請參閱您的 setitimer(2) 文件。

getitimer ( $which )

傳回 $which 指定的間隔計時器中剩餘的時間。

在純量內容中,傳回剩餘時間。

在清單內容中,傳回剩餘時間和間隔。間隔總是您使用 setitimer() 輸入的內容。

clock_gettime ( $which )

傳回 $which 指定的 POSIX 高解析度計時器的目前值(以秒為單位)。支援 POSIX 高解析度計時器的所有實作都應該至少支援 CLOCK_REALTIME$which 值,這應該會傳回接近 gettimeofday 結果的結果,或自 1970 年 1 月 1 日格林威治標準時間 (GMT) 00:00:00:00 以來的秒數。不要假設 CLOCK_REALTIME 為零,它可能是 1 或其他值。另一個可能很有用的值(但並非所有地方都可用)是 CLOCK_MONOTONIC,它保證時間值會單調遞增(與 time() 或 gettimeofday() 不同,後者可以調整)。請參閱系統文件,了解其他可能支援的值。

clock_getres ( $which )

傳回 $which 指定的 POSIX 高解析度計時器的解析度(以秒為單位)。支援 POSIX 高解析度計時器的所有實作都應該至少支援 CLOCK_REALTIME$which 值,請參閱 "clock_gettime"

注意:傳回的解析度可能過於樂觀。即使解析度很高(數字很小),這只表示您將能夠以該解析度指定 clock_gettime() 和 clock_nanosleep() 的參數。系統可能無法以該解析度實際測量事件,而且各種開銷和整體系統負載必定會影響任何計時。

clock_nanosleep ( $which, $nanoseconds, $flags = 0)

休眠指定的奈秒數(1e9 分之一秒)。傳回實際休眠的奈秒數。$which 是「時脈識別碼」,與 clock_gettime() 和 clock_getres() 相同。旗標預設為零,但可以指定 TIMER_ABSTIME(必須明確匯出),表示 $nanoseconds 不是時間間隔(這是預設值),而是絕對時間。可以休眠超過一秒。也可以休眠零秒,這通常會像「執行緒讓步」一樣運作。另請參閱 Time::HiRes::sleep()Time::HiRes::usleep()Time::HiRes::nanosleep()

不要指望 clock_nanosleep() 能精確到一奈秒。即使能精確到一千奈秒也很好了。

clock()

以秒為單位傳回自第一次呼叫 clock() 以來,處理程序所花費的「處理程序時間」(使用者 + 系統時間)(定義不是「自處理程序開始以來」,儘管如果幸運的話,這些時間可能會非常接近,具體取決於系統)。這表示您可能需要儲存第一次呼叫 clock() 的結果,並從 clock() 的後續結果中減去該值。

傳回的時間還包括已執行 wait() 的已終止子處理程序的處理程序時間。此值有點像核心 Perl 的 times() 傳回的第二個值,但未必相同。請注意,由於向後相容性的限制,傳回值可能會在約 2147 秒或約 36 分鐘時換行。

stat
stat FH
stat EXPR
lstat
lstat FH
lstat EXPR

如同 perlfunc 中的 "stat""lstat",但如果作業系統和檔案系統都支援此類時間戳記,則存取/修改/變更檔案時間戳記的解析度為亞秒。若要覆寫標準 stat()

use Time::HiRes qw(stat);

測試 &Time::HiRes::d_hires_stat 的值,以找出作業系統是否支援亞秒檔案時間戳記:大於零的值表示是。遺憾的是,沒有簡單的方法可以找出檔案系統是否支援此類時間戳記。UNIX 檔案系統通常支援;NTFS 支援;FAT 不支援(FAT 時間戳記粒度為秒)。

&Time::HiRes::d_hires_stat 的零傳回值表示 Time::HiRes::stat 是 CORE::stat() 的無操作傳遞(lstat 也是如此),因此時間戳記將保持為整數。即使 &Time::HiRes::d_hires_stat 為非零,如果檔案系統不執行亞秒時間戳記,也會發生相同的情況。

無論如何,不要期待奈秒解析度,甚至微秒解析度。另外請注意,修改/存取時間戳記可能具有不同的解析度,而且不需要同步,例如如果作業為

write
stat # t1
read
stat # t2

t2 的存取時間戳記不需要大於 t1 的修改時間戳記:它可能相等或小於

utime LIST

如同 "utime" in perlfunc,但具有設定存取/修改檔案時間戳記的子秒解析度功能,如果作業系統和檔案系統,以及檔案系統的掛載選項,全部支援此類時間戳記。

若要覆寫標準 utime()

use Time::HiRes qw(utime);

測試 &Time::HiRes::d_hires_utime 的值,以找出作業系統是否支援設定子秒檔案時間戳記。

如同 CORE::utime(),將未定義傳遞為 atime 和 mtime,會使用 NULL 參數呼叫系統呼叫。

實際可達到的子秒解析度取決於作業系統和檔案系統的組合。

修改時間戳記可能完全不可行:例如,noatime 檔案系統掛載選項可能會禁止您變更存取時間戳記。

傳回成功變更的檔案數目。

範例

use Time::HiRes qw(usleep ualarm gettimeofday tv_interval);

$microseconds = 750_000;
usleep($microseconds);

# signal alarm in 2.5s & every .1s thereafter
ualarm(2_500_000, 100_000);
# cancel that ualarm
ualarm(0);

# get seconds and microseconds since the epoch
($s, $usec) = gettimeofday();

# measure elapsed time
# (could also do by subtracting 2 gettimeofday return values)
$t0 = [gettimeofday];
# do bunch of stuff here
$t1 = [gettimeofday];
# do more stuff here
$t0_t1 = tv_interval $t0, $t1;

$elapsed = tv_interval ($t0, [gettimeofday]);
$elapsed = tv_interval ($t0); # equivalent code

#
# replacements for time, alarm and sleep that know about
# floating seconds
#
use Time::HiRes;
$now_fractions = Time::HiRes::time;
Time::HiRes::sleep (2.5);
Time::HiRes::alarm (10.6666666);

use Time::HiRes qw ( time alarm sleep );
$now_fractions = time;
sleep (2.5);
alarm (10.6666666);

# Arm an interval timer to go off first at 10 seconds and
# after that every 2.5 seconds, in process virtual time

use Time::HiRes qw ( setitimer ITIMER_VIRTUAL time );

$SIG{VTALRM} = sub { print time, "\n" };
setitimer(ITIMER_VIRTUAL, 10, 2.5);

use Time::HiRes qw( clock_gettime clock_getres CLOCK_REALTIME );
# Read the POSIX high resolution timer.
my $high = clock_gettime(CLOCK_REALTIME);
# But how accurate we can be, really?
my $reso = clock_getres(CLOCK_REALTIME);

use Time::HiRes qw( clock_nanosleep TIMER_ABSTIME );
clock_nanosleep(CLOCK_REALTIME, 1e6);
clock_nanosleep(CLOCK_REALTIME, 2e9, TIMER_ABSTIME);

use Time::HiRes qw( clock );
my $clock0 = clock();
... # Do something.
my $clock1 = clock();
my $clockd = $clock1 - $clock0;

use Time::HiRes qw( stat );
my ($atime, $mtime, $ctime) = (stat("istics"))[8, 9, 10];

C API

除了上述 perl API 之外,擴充套件撰寫人員可以使用 C API。下列 C 函式在 modglobal hash 中提供

name             C prototype
---------------  ----------------------
Time::NVtime     NV (*)()
Time::U2time     void (*)(pTHX_ UV ret[2])

兩個函式都傳回等效資訊 (例如 gettimeofday),但表示方式不同。名稱 NVtimeU2time 的選擇主要基於它們與作業系統無關。(gettimeofday 以 Unix 為中心,儘管某些平台(例如 Win32 和 VMS)有其模擬。)

以下是從 C 使用 NVtime 的範例

NV (*myNVtime)(); /* Returns -1 on failure. */
SV **svp = hv_fetchs(PL_modglobal, "Time::NVtime", 0);
if (!svp)         croak("Time::HiRes is required");
if (!SvIOK(*svp)) croak("Time::NVtime isn't a function pointer");
myNVtime = INT2PTR(NV(*)(), SvIV(*svp));
printf("The current time is: %" NVff "\n", (*myNVtime)());

診斷

useconds 或間隔大於 ...

在 ualarm() 中,您嘗試使用超過 1_000_000 的微秒數或間隔(也以微秒為單位),而您的系統中沒有 setitimer() 可模擬該情況。

尚未發明負時間

您嘗試使用負時間參數。

內部錯誤:useconds < 0(未簽署...已簽署...)

發生嚴重錯誤 - 無法變為負數的微秒數剛剛變為負數。也許您的編譯器損壞了?

useconds 或 uinterval 等於或大於 1000000

在某些平台上,不可能獲得具有亞秒解析度且大於一秒的警報。

在此平台中未實現

某些呼叫在每個平台上都不可用,無論是真實的還是模擬的。

注意事項

請注意,核心 time() 可能會捨入而不是截斷。這意味著核心 time() 可能會將時間報告為比 gettimeofday()Time::HiRes::time() 晚一秒。

調整系統時鐘(手動或通過 ntp 等服務)可能會導致問題,特別是對於假設時間單調遞增的長期運行程式(請注意,並非所有平台都能像 UNIX ntp 那樣優雅地調整時間)。例如,在 Win32(和 Cygwin 和 MinGW 等衍生平台)中,Time::HiRes::time() 可能會暫時偏離系統時鐘(和原始 time())最多 0.5 秒。Time::HiRes 最終會注意到這一點並重新校準。請注意,自 Time::HiRes 1.77 以來,clock_gettime(CLOCK_MONOTONIC) 可能有助於此(如果您的系統支援 CLOCK_MONOTONIC)。

某些系統有 API 但沒有實作:例如,QNX 和 Haiku 有間隔計時器 API 但沒有功能。

在 Sierra 之前的 macOS(10.12 之前的 OS X)中,clock_getres()、clock_gettime() 和 clock_nanosleep() 使用 Mach 計時器進行模擬;作為模擬的副作用,CLOCK_REALTIME 和 CLOCK_MONOTONIC 是同一個計時器。

gnukfreebsd 似乎有無法運作的 futimens() 和 utimensat()(至少在 10.1 中):因此高解析度 utime() 無法運作。

另請參閱

Perl 模組 BSD::ResourceTime::TAI64

系統文件中的 clock(3)clock_gettime(2)clock_getres(3)clock_nanosleep(3)clock_settime(2)getitimer(2)gettimeofday(2)setitimer(2)sleep(3)stat(2)ualarm(3)

作者

D. Wegscheid <wegscd@whirlpool.com> R. Schertler <roderick@argon.org> J. Hietaniemi <jhi@iki.fi> G. Aas <gisle@aas.no>

版權和授權

版權所有 (c) 1996-2002 Douglas E. Wegscheid。保留所有權利。

版權所有 (c) 2002、2003、2004、2005、2006、2007、2008 Jarkko Hietaniemi。保留所有權利。

版權所有 (C) 2011、2012、2013 Andrew Main (Zefram) <zefram@fysh.org>

此程式為自由軟體;您可以在與 Perl 相同的條款下重新散布或修改它。