php的內建函數file_get_contents想必當初是為讀取硬碟檔案設計的,所以在讀取檔案內容時如果磁碟繁忙或準備資料慢,file_get_contents會進入忙等待,期許資料會飛快的到來,而不會等哪怕1ms。但是這個東東也允許用來讀取http內容,而且等待資料的行為和讀取檔案一樣,而等待http返回和等待磁碟準備資料在時間上可不是一個量級的,所以當file_get_contents用來讀取http內容時就進入了秒級的忙等待,從而導致cpu飆升。不過貌似新版本的php修複了該問題,或者和某些編譯項有關。
情景見下:
strace -rv -p <PHP進程ID> -o strace.log
cat strace.log
----------------------------------------------
0.000019 select(8, [7], [7], [], {15, 0}) = 1 (out [7], left {15, 0}) <0.000006>
0.000029 poll([{fd=7, events=POLLIN|POLLPRI}], 1, 0) = 0 <0.000004>
0.000018 gettimeofday({1340090123, 417745}, NULL) = 0 <0.000004>
0.000017 gettimeofday({1340090123, 417763}, NULL) = 0 <0.000005>
0.000019 gettimeofday({1340090123, 417781}, NULL) = 0 <0.000005>
0.000019 select(8, [7], [7], [], {15, 0}) = 1 (out [7], left {15, 0}) <0.000010>
0.000034 poll([{fd=7, events=POLLIN|POLLPRI}], 1, 0) = 0 <0.000005>
0.000018 gettimeofday({1340090123, 417853}, NULL) = 0 <0.000005>
0.000018 gettimeofday({1340090123, 417871}, NULL) = 0 <0.000005>
0.000019 gettimeofday({1340090123, 417889}, NULL) = 0 <0.000005>
0.000019 select(8, [7], [7], [], {15, 0}) = 1 (out [7], left {15, 0}) <0.000006>
0.000028 poll([{fd=7, events=POLLIN|POLLPRI}], 1, 0) = 0 <0.000005>
0.000018 gettimeofday({1340090123, 417956}, NULL) = 0 <0.000007>
0.000020 gettimeofday({1340090123, 417974}, NULL) = 0 <0.000005>
0.000018 gettimeofday({1340090123, 417993}, NULL) = 0 <0.000004>
0.000032 select(8, [7], [7], [], {15, 0}) = 1 (out [7], left {15, 0}) <0.000006>
0.000036 poll([{fd=7, events=POLLIN|POLLPRI}], 1, 0) = 0 <0.000005>
0.000019 gettimeofday({1340090123, 418080}, NULL) = 0 <0.000005>
0.000018 gettimeofday({1340090123, 418097}, NULL) = 0 <0.000005>
0.000020 gettimeofday({1340090123, 418117}, NULL) = 0 <0.000005>
... ...
----------------------------------------------
php進入了持續數秒的非阻塞poll迴圈,直到資料返回,cpu使用率在此期間會飆升。
對於讀取http內容,最好避免用file_get_contents,可以改用下面的自訂函數取代:
function url_get_contents($strUrl, $boolUseCookie=false){$ch = curl_init($strUrl);curl_setopt($ch, CURLOPT_HEADER, 0);curl_setopt($ch, CURLOPT_TIMEOUT, 5);curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);curl_setopt($ch, CURLOPT_HTTPGET, true); curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);curl_setopt($ch, CURLOPT_REFERER, $_SERVER['HTTP_REFERER']); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);curl_setopt($ch, CURLOPT_MAXREDIRS, 3);if ($boolUseCookie && is_array($_COOKIE) && count($_COOKIE) > 0) {$cookie_str = '';foreach($_COOKIE as $key => $value) {$cookie_str .= "$key=$value; "; }curl_setopt($ch, CURLOPT_COOKIE, $cookie_str);}$response = curl_exec($ch);if (curl_errno($ch) != 0) {return false;}curl_close($ch);return $response;}