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 介面,用於 usleep
、nanosleep
、ualarm
、gettimeofday
和 setitimer
/getitimer
系統呼叫,換句話說,就是高解析度時間和計時器。請參閱下方的 "範例" 區段和測試腳本,以了解使用方式;請參閱系統文件,以了解底層 nanosleep
或 usleep
、ualarm
、gettimeofday
和 setitimer
/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 秒的行為最終很可能會睡眠 超過該時間,但如果您最終睡眠的時間略 少於該時間,也請不要感到驚訝。
下列函式可以從此模組匯入。預設不會匯出任何函式。
在陣列內容中傳回一個包含自紀元以來秒數和微秒數的二元素陣列。在純量內容中傳回浮點秒數,例如 Time::HiRes::time()
(見下文)。
睡眠指定的微秒數(百萬分之一秒)。傳回實際睡眠的微秒數。可以睡眠超過一秒,這與 usleep
系統呼叫不同。也可以睡眠零秒,這通常會像 執行緒讓步 一樣運作。另請參閱 Time::HiRes::sleep()
和 clock_nanosleep()
。
請勿期望 usleep() 精確到一微秒。
睡眠指定的奈秒數(十億分之一秒)。傳回實際睡眠的奈秒數(僅精確到微秒,最接近一千個奈秒)。可以睡眠超過一秒。也可以睡眠零秒,這通常會像 執行緒讓步 一樣運作。另請參閱 Time::HiRes::sleep()
、Time::HiRes::usleep()
和 clock_nanosleep()
。
請勿期望 nanosleep() 精確到一奈秒。即使獲得一千奈秒的精確度也很不錯了。
發出 ualarm
呼叫;$interval_useconds
是選用的,如果未指定,將為零,導致類似 alarm
的行為。
以微秒為單位傳回警報中的剩餘時間,或在發生錯誤時傳回 undef
。
ualarm(0) 將取消未完成的 ualarm()。
請注意,警報和睡眠之間的互動未指定。
tv_interval ( $ref_to_gettimeofday [, $ref_to_later_gettimeofday] )
傳回兩個時間之間的浮動秒數,應由 gettimeofday()
傳回。如果省略第二個參數,則使用目前時間。
傳回自紀元以來的浮動秒數。可以匯入此函式,導致直接替換核心 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()
函式,它會將秒數和微秒作為兩個獨立的值提供給您。
睡眠指定秒數。傳回實際睡眠的秒數(浮點值)。可以匯入此函式,導致直接替換 perl 提供的 sleep
;請參閱下方的 "範例"。
請注意,警報和睡眠之間的互動未指定。
在指定秒數後發送 SIGALRM
訊號。如果可用,則使用 setitimer()
實作,否則使用 ualarm()
。$interval_floating_seconds
參數是選用的,如果未指定,將為零,導致類似 alarm()
的行為。可以匯入此函式,導致直接替換 perl 提供的 alarm
;請參閱下方的 "範例"。
傳回鬧鐘剩餘時間(以秒為單位),或在發生錯誤時傳回 undef
。
註 1:在某些作業系統和 Perl 版本組合中,SIGALRM
會重新啟動 select()
,而不是中斷它。這表示 alarm()
後接 select()
可能會花費 alarm()
和 select()
指定時間的總和,而不僅僅是 alarm()
的時間。
請注意,警報和睡眠之間的互動未指定。
啟動間隔計時器:在一段時間後,會收到一個訊號 ($which),而且可能會在特定間隔收到更多訊號。若要停用「計時器」,請使用零的 $floating_seconds
。如果 $interval_floating_seconds
設為零(或未指定),則計時器會在傳送下一個訊號後停用。
使用間隔計時器可能會干擾 alarm()
、sleep()
和 usleep()
。標準說法是「互動未指定」,這表示任何事都可能發生:它可能會運作,也可能不會。
在純量內容中,會傳回計時器中剩餘的時間。
在清單內容中,會傳回剩餘時間和間隔。
通常有三個或四個間隔計時器(訊號)可用:$which
可以是 ITIMER_REAL
、ITIMER_VIRTUAL
、ITIMER_PROF
或 ITIMER_REALPROF
。請注意,哪些可用取決於:真正的 UNIX 平台通常有前三個,但只有 Solaris 似乎有 ITIMER_REALPROF
(用於分析多執行緒程式)。很不幸地,Win32 沒有間隔計時器。
ITIMER_REAL
會產生類似 alarm()
的行為。時間以實際時間計算;也就是說,時鐘時間。當計時器到期時,會傳送 SIGALRM
。
ITIMER_VIRTUAL
以(處理)虛擬時間計算時間;也就是說,僅在處理執行時。在多處理器/使用者/CPU 系統中,這可能會多於或少於實際時間或時鐘時間。(此時間也稱為使用者時間。)當計時器到期時,會傳送 SIGVTALRM
。
ITIMER_PROF
在處理虛擬時間或作業系統代表處理執行(例如 I/O)時計算時間。(此時間也稱為系統時間。)(使用者時間和系統時間的總和稱為CPU 時間。)當計時器到期時,會傳送 SIGPROF
。SIGPROF
可以中斷系統呼叫。
多執行緒程式的間隔計時器語意取決於系統,而且有些系統可能會支援額外的間隔計時器。例如,未指定哪個執行緒會收到訊號。請參閱您的 setitimer(2)
文件。
傳回 $which
指定的間隔計時器中剩餘的時間。
在純量內容中,傳回剩餘時間。
在清單內容中,傳回剩餘時間和間隔。間隔總是您使用 setitimer()
輸入的內容。
傳回 $which
指定的 POSIX 高解析度計時器的目前值(以秒為單位)。支援 POSIX 高解析度計時器的所有實作都應該至少支援 CLOCK_REALTIME
的 $which
值,這應該會傳回接近 gettimeofday
結果的結果,或自 1970 年 1 月 1 日格林威治標準時間 (GMT) 00:00:00:00 以來的秒數。不要假設 CLOCK_REALTIME 為零,它可能是 1 或其他值。另一個可能很有用的值(但並非所有地方都可用)是 CLOCK_MONOTONIC
,它保證時間值會單調遞增(與 time() 或 gettimeofday() 不同,後者可以調整)。請參閱系統文件,了解其他可能支援的值。
傳回 $which
指定的 POSIX 高解析度計時器的解析度(以秒為單位)。支援 POSIX 高解析度計時器的所有實作都應該至少支援 CLOCK_REALTIME
的 $which
值,請參閱 "clock_gettime"。
注意:傳回的解析度可能過於樂觀。即使解析度很高(數字很小),這只表示您將能夠以該解析度指定 clock_gettime() 和 clock_nanosleep() 的參數。系統可能無法以該解析度實際測量事件,而且各種開銷和整體系統負載必定會影響任何計時。
休眠指定的奈秒數(1e9 分之一秒)。傳回實際休眠的奈秒數。$which 是「時脈識別碼」,與 clock_gettime() 和 clock_getres() 相同。旗標預設為零,但可以指定 TIMER_ABSTIME
(必須明確匯出),表示 $nanoseconds
不是時間間隔(這是預設值),而是絕對時間。可以休眠超過一秒。也可以休眠零秒,這通常會像「執行緒讓步」一樣運作。另請參閱 Time::HiRes::sleep()
、Time::HiRes::usleep()
和 Time::HiRes::nanosleep()
。
不要指望 clock_nanosleep() 能精確到一奈秒。即使能精確到一千奈秒也很好了。
以秒為單位傳回自第一次呼叫 clock() 以來,處理程序所花費的「處理程序時間」(使用者 + 系統時間)(定義不是「自處理程序開始以來」,儘管如果幸運的話,這些時間可能會非常接近,具體取決於系統)。這表示您可能需要儲存第一次呼叫 clock() 的結果,並從 clock() 的後續結果中減去該值。
傳回的時間還包括已執行 wait() 的已終止子處理程序的處理程序時間。此值有點像核心 Perl 的 times() 傳回的第二個值,但未必相同。請注意,由於向後相容性的限制,傳回值可能會在約 2147 秒或約 36 分鐘時換行。
如同 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" 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];
除了上述 perl API 之外,擴充套件撰寫人員可以使用 C API。下列 C 函式在 modglobal hash 中提供
name C prototype
--------------- ----------------------
Time::NVtime NV (*)()
Time::U2time void (*)(pTHX_ UV ret[2])
兩個函式都傳回等效資訊 (例如 gettimeofday
),但表示方式不同。名稱 NVtime
和 U2time
的選擇主要基於它們與作業系統無關。(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)());
在 ualarm() 中,您嘗試使用超過 1_000_000 的微秒數或間隔(也以微秒為單位),而您的系統中沒有 setitimer() 可模擬該情況。
您嘗試使用負時間參數。
發生嚴重錯誤 - 無法變為負數的微秒數剛剛變為負數。也許您的編譯器損壞了?
在某些平台上,不可能獲得具有亞秒解析度且大於一秒的警報。
某些呼叫在每個平台上都不可用,無論是真實的還是模擬的。
請注意,核心 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::Resource、Time::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 相同的條款下重新散布或修改它。