sleep 和 usleep 的概念是讓 CPU 執行一些閒置週期,以便其他程式可以執行它們自己的週期。這會產生更好的回應時間和更低的整體系統負載。因此,如果您必須等待某些事情,請睡眠幾秒鐘,而不是在什麼都不做,只是等待時佔用 CPU。
(PHP 4, PHP 5, PHP 7, PHP 8)
usleep — 延遲執行,以微秒為單位
microseconds
以微秒為單位的暫停時間。一微秒是一百萬分之一秒。
注意: 大於
1000000
的值(即睡眠超過一秒)可能不受作業系統支援。請改用 sleep()。
注意: 系統活動、處理呼叫所花費的時間或系統計時器的粒度可能會使睡眠時間稍微延長(即可能長於
microseconds
)。
不傳回任何值。
範例 1 usleep() 範例
<?php
// 目前時間
echo (new DateTime('now'))->format('H:i:s.v'), "\n";
// 等待 2 毫秒
usleep(2000);
// 回來了!
echo (new DateTime('now'))->format('H:i:s.v'), "\n";
// 等待 30 毫秒
usleep(30000);
// 又回來了!
echo (new DateTime('now'))->format('H:i:s.v'), "\n";
?>
以上範例會輸出
11:13:28.005 11:13:28.007 11:13:28.037
sleep 和 usleep 的概念是讓 CPU 執行一些閒置週期,以便其他程式可以執行它們自己的週期。這會產生更好的回應時間和更低的整體系統負載。因此,如果您必須等待某些事情,請睡眠幾秒鐘,而不是在什麼都不做,只是等待時佔用 CPU。
在 MacOS X 和 Linux 上,usleep() 呼叫似乎會消耗 CPU 週期,而 sleep() 和 time_nanosleep() 則不會。在 PHP 5.3.29 和 5.5.29 上也是如此。
我使用一個只有呼叫 sleep/usleep/time_nanosleep 的迴圈,並將它們與一個空的迴圈進行比較。顯然,空的迴圈消耗了 99% 的 CPU,sleep 使用了 0%,usleep 對於 1000 毫秒使用了 3%,對於 100 毫秒使用了 6%,而 time_nanosleep 對於 500 毫秒和 1000 毫秒都使用了 0%。
應該注意的是,當在 kernel32.dll 中使用 Sleep() 函式時,Windows 機器的解析度為 10 毫秒或 15 毫秒(取決於晶片組實作和所使用的 HAL)。這表示您的平均誤差將為 5 毫秒或 7.5 毫秒。除非您真的需要睡眠的時間少於 Windows 提供的粒度,否則這通常不是問題。
應該注意的是,以非常快的速度迴圈來產生延遲的函式也會在迴圈時消耗 100% 的 CPU。嘗試建立一個執行 100000 次的虛擬迴圈,看看它如何阻塞您的機器。如果您真的需要 usleep(),請不要使用 Windows。
如果您使用 Windows,那麼如果您真的需要使用 usleep,您可能會遇到麻煩。
使用 fsockopen 的 Bernie 的微延遲函式無法正常運作,並且 fclose 也沒有太大幫助。
我不知道網路連線是否會變得奇怪,但我知道它無法運作,因為您已對其發出超過 2000 - 3000 次呼叫,因此它在「長壽命」php 腳本中並不是可靠的解決方案,或者這些是我在 PHP 和 PHP-GTK 應用程式中微延遲函式的問題。
雖然應該找到另一種解決方案,而且在 Google 上搜尋了一下,我找到了一個 WinAPI 函式:Sleep。
所以我使用這個對我來說運作正常的程式碼片段,您會獲得毫秒的精確度,但更重要的是,它可以長期運作腳本,而且當然,它不會浪費任何 CPU 週期。
dl('php_w32api.dll');
$GLOBALS['win32api'] =& new win32;
// 適用於 Windows 和 PHP4 的 USleep 替代方案
$GLOBALS['win32api']->registerfunction("long Sleep (long dwMillisecods) From kernel32.dll");
// 現在您可以在腳本中的任何位置呼叫此函式:$GLOBALS['win32api']->Sleep(milliseconds);
for ($msec = 2000; $msec > 0; $msec = $msec - 125) {
echo "嗨。下一個在 $msec 毫秒。\n";
$GLOBALS['win32api']->Sleep($msec);
}
關於使用 fsockopen 發佈的 microdelay() 程式碼,有一個警告 - 如果您在迴圈中使用它來延遲很短的時間,您將很快耗盡插槽/插槽緩衝區空間。然後您的網路連線會變得非常奇怪......
我花費了數天的時間嘗試為 Windows 建立可靠的 usleep() 替代方案。
我只有這個可以提供
正如其他人已經評論的那樣,下面使用的 gettimeofday() 方法是無用的 - PHP 將在什麼都不做的情況下使用所有可用的 CPU 效能。
顯然地, `fsockopen()` 方法也沒用 – 如同其他人評論的,原始文章中缺少 `fclose()`,但這顯然無法解決問題。在呼叫此函數大約 50 次左右後,`fsockopen()` 會立即返回,沒有任何延遲 – 而在 Windows 中監看進程監視器時,你會看到進程佔用的記憶體越來越多,直到最終 PHP 在達到最大值時中止(或崩潰)。
`win32api` 方法也行不通…在呼叫 `Sleep` 函數數百次後(在此期間,由於某處的記憶體洩漏,每次記憶體使用量也會上升),PHP 會產生異常,而 Windows 將終止它。
我已經放棄了 – 我認為在 PHP 4 下,這個問題沒有任何可行的解決方案。
如果您需要此功能,請將您的專案升級到 PHP 5。
或者使用 `sleep()` 函數,將延遲時間設定為 1 秒。
不幸的是,這些似乎是您唯一的選擇...
老兄,你的這段程式碼真是太棒了。它運作得非常好。我只是想指出一些事情,並提供我自己的改進。
1. 如果您像我一樣,您可能想知道為什麼每次呼叫時都必須重新建立 socket,以及為什麼不能只建立一個靜態 socket。那是因為 `socket_select` 假設您傳遞的是一個指標,並且會在返回時更改變數,以反映實際被更改的 sockets。
2. 我想不通為什麼 `socket_select` 沒有被定義。那是因為您沒有在 php.ini 中啟用正確的擴充功能。
好的,這是我的稍微改進版本。我做的唯一真正的事情是使用一個靜態變數來表示 socket,以避免每次呼叫此函數時都建立一個全新的 socket。我不確定 socket 的建立是否會像這裡報告的其他問題一樣導致程式崩潰,但如果你問我,還是謹慎一點比較好。
function Sleeper($mSec)
{
// 給像我一樣花了 5 分鐘
// 想知道為什麼 `socket_create` 沒有被定義的笨蛋們
if(!function_exists('socket_create')){
die("請啟用擴充功能 php_sockets.dll");
}
// 這樣 socket 只會被建立一次
static $socket=false;
if($socket===false){
$socket=array(socket_create(AF_INET,SOCK_RAW,0));
}
$pSock=$socket;
// 計算時間
$uSex = $mSec * 1000;
// 執行等待
socket_select($read=NULL,$write=NULL,$pSock,0,$uSex);
// 強迫症
return true;
}
要監控腳本的 CPU 使用率並避免任何惡意的 CPU 佔用循環,您可以使用此函數(在 Windows 或安全模式下無法運作)。我知道它在 FreeBSD 上可以運作。
function phpmon($max)
{
$cmd = `ps -Unobody -r -o%cpu`;
$lines = explode("\n", $cmd);
$usage = substr($lines[1], 0, strpos($lines[1], "."));
$sleeprate = 500;
while ($usage >= $max)
{
$cmd = `ps -Unobody -r -o%cpu`;
$lines = explode("\n", $cmd);
$usage = substr($lines[1], 0, strpos($lines[1], "."));
usleep($sleeprate);
}
}
phpmon($MAX);
其中 $MAX 是您希望進程消耗的最大 CPU 百分比。如果有任何改進/建議,請寄電子郵件給我。
我注意到這會消耗大量的系統 CPU(至少在我的有限測試中),可能是由於所有系統呼叫或我用來測試腳本有效性的龐大數學函數。
請注意,此函數有開銷!
範例
<?php
for ($i = 0; $i < 1000000; ++$i)
{
usleep(1);
}
?>
此程式碼區塊在我的伺服器上運行約 70 秒。
每個 `usleep()` 函數呼叫,腳本大約需要 70 微秒。