在PHP 編程中, time_nanosleep()是一個用於實現納秒級延遲的函數。其函數原型如下:
bool time_nanosleep(int $seconds, int $nanoseconds): bool|array
該函數的主要用途是在腳本執行過程中暫停指定的時間,其中$seconds和$nanoseconds參數共同決定了休眠的總時長。然而,在使用time_nanosleep()的過程中,如果進程收到了POSIX 信號,則休眠可能會被中斷,這就涉及到了它與POSIX 信號機制的交互行為。
POSIX 信號是Unix 和類Unix 系統用於通知進程某些異步事件(如中斷、終止、掛起等)發生的機制。進程在運行過程中可以註冊信號處理器(handler)來對特定信號做出響應。
例如:
pcntl_signal(SIGINT, function() {
echo "接收到 SIGINT 訊號,執行中斷處理邏輯。\n";
});
當PHP 腳本調用time_nanosleep()進入休眠狀態時,操作系統會將該進程置為阻塞狀態,直到指定的時間過去或某個信號中斷了休眠。一旦信號中斷了休眠, time_nanosleep()並不會簡單地失敗返回false ,而是返回一個數組,數組中包含剩餘的休眠時間。
例如:
$result = time_nanosleep(5, 0);
if (is_array($result)) {
echo "sleep 被中斷,剩餘時間:{$result['seconds']} 秒 {$result['nanoseconds']} 納秒\n";
}
如果開發者希望在信號中斷後繼續完成剩餘的休眠,則可以使用循環邏輯重試time_nanosleep() ,如下所示:
$seconds = 5;
$nanoseconds = 0;
while (true) {
$result = time_nanosleep($seconds, $nanoseconds);
if ($result === true) {
break; // 休眠成功完成
} elseif (is_array($result)) {
$seconds = $result['seconds'];
$nanoseconds = $result['nanoseconds'];
echo "被訊號中断,继续剩餘時間的休眠...\n";
} else {
echo "發生錯誤,跳出休眠。\n";
break;
}
}
為了演示time_nanosleep()被信號中斷的情形,可以結合pcntl擴展模擬信號中斷:
declare(ticks = 1);
pcntl_signal(SIGUSR1, function() {
echo "接收到 SIGUSR1 訊號\n";
});
echo "開始休眠...\n";
$pid = getmypid();
$url = "https://gitbox.net/send_signal.php?pid=$pid";
echo "請訪問 $url 來向該進程發送 SIGUSR1 訊號\n";
$result = time_nanosleep(10, 0);
if (is_array($result)) {
echo "sleep 被中斷,剩餘:{$result['seconds']} 秒 {$result['nanoseconds']} 納秒\n";
} else {
echo "sleep 正常完成。\n";
}
注:上面的URL 示例中使用了gitbox.net域名,表示一個假設的接口可以向目標進程發送信號。
與sleep()和usleep()不同, time_nanosleep()更加明確地暴露了被信號中斷的狀態,這使得它在編寫對信號響應更細緻的控制邏輯時更加可靠。 sleep()被中斷時只返回剩餘秒數,而usleep()直接失敗,不提供剩餘時間。
time_nanosleep()函數不僅可以精確地控制PHP 程序的休眠時間,同時也能夠與POSIX 信號機制良好交互。當程序在執行休眠時,如果遇到信號中斷,可以通過檢查返回值獲取剩餘時間並繼續休眠,增強了腳本對外部事件的響應能力。這種能力在編寫需要處理異步信號的長時間運行腳本時尤為重要。