原文發表在http://www.trackself.com/archives/463.html
PHP cURL 所有函數列表:
http://php.net/manual/zh/ref.curl.php
以下是PHP中cURL多線程相關函數:
curl_multi_add_handle — 向curl批處理會話中添加單獨的curl句柄 curl_multi_close — 關閉一組cURL句柄 curl_multi_exec — 運行當前 cURL 句柄的子連接 curl_multi_getcontent — 如果設置了CURLOPT_RETURNTRANSFER,則返回獲取的輸出的文本流 curl_multi_info_read — 獲取當前解析的cURL的相關傳輸信息 curl_multi_init — 返回一個新cURL批處理句柄 curl_multi_remove_handle — 移除curl批處理句柄資源中的某個句柄資源 curl_multi_select — 等待所有cURL批處理中的活動連接 curl_multi_setopt — 爲 cURL 並行處理設置一個選項 curl_multi_strerror — Return string describing error code
一般來說,想到要用這些函數時,目的顯然應該是要同時請求多個URL,而不是一個一個依次請求,否則不如自己循環去調curl_exec好了。
步驟總結如下:
1、調用 curl_multi_init,初始化一個批處理handle
2、循環調用 curl_multi_add_handle,往1中的批處理handle 添加curl_init來的子handle
3、持續調用 curl_multi_exec,直到所有子handle執行完畢。
4、根據需要循環調用 curl_multi_getcontent 獲取結果
5、調用 curl_multi_remove_handle,併爲每個字handle調用curl_close
6、調用 curl_multi_close
<?php /* cmi該函數的目的在於併發請求多個url,然後返回http://www.trackself.com編寫,真正的PHP併發 原文發表在http://www.trackself.com/archives/463.html 此併發請求在url多於2的時候,明顯比for ... file_get_contents ...要優很多 核心是curl庫的curl_multi方法 用法: $urls=array( 'http://www.google.com', 'http://www.baidu.com', 'http://sina.com', 'http://163.com' ) $htmls=cmi($urls); print_r($htmls); //傳入的$connomains是URL一維數組,由http://www.trackself.com編寫 //該函數的目的在於併發請求多個url,然後返回源碼 //以一次性略增加CPU爲代價 //來減輕服務器因爲for ... file_get_contents ...的長時連接負擔及內存和CPU的負擔,所以併發數不要大多(50以內效果非常好),儘量不要用於單頁面或3頁面以內的請求 //$killspace爲真時表示自動去掉HTML中換行及多餘的空白,$forhtml爲真時表示反回源碼,爲faluse時就是併發執行請求了(可以用於計劃任務) //後面的幾個參數的詳細說明請看註釋,畢竟函數不長 */ function cmi($connomains, $killspace = TRUE, $forhtml = TRUE, $timeout = 6, $header = 0, $follow = 1) { $res = array(); $urlsa = array(); $results = array(); $mh = curl_multi_init(); //創建多curl對象,爲了幾乎同時執行 foreach ($connomains as $i => $url) { $conn[$i] = curl_init($url); //若url中含有gb2312漢字,例如FTP時,要在傳入url的時候處理一下,這裏不用 curl_setopt($conn[$i], CURLOPT_TIMEOUT, $timeout); //此時間須根據頁面的HTML源碼出來的時間,一般是在1s內的,慢的話應該也不會6秒,極慢則是在16秒內 curl_setopt($conn[$i], CURLOPT_HEADER, $header); //不返回請求頭,只要源碼 curl_setopt($conn[$i], CURLOPT_RETURNTRANSFER, 1); //必須爲1 curl_setopt($conn[$i], CURLOPT_FOLLOWLOCATION, $follow); //如果頁面含有自動跳轉的代碼如301或者302HTTP時,自動拿轉向的頁面 curl_multi_add_handle($mh, $conn[$i]); //關鍵,一定要放在上面幾句之下,將單curl對象賦給多對象 } //下面一大步的目的是爲了減少cpu的無謂負擔,暫時不明,來自php.net的建議,幾乎是固定用法 do { $mrc = curl_multi_exec($mh, $active); //當無數據時或請求暫停時,active=true } while ($mrc == CURLM_CALL_MULTI_PERFORM); //當正在接受數據時 while ($active and $mrc == CURLM_OK) {//當無數據時或請求暫停時,active=true,爲了減少cpu的無謂負擔,這一步很難明啊 if (curl_multi_select($mh) != -1) { do { $mrc = curl_multi_exec($mh, $active); } while ($mrc == CURLM_CALL_MULTI_PERFORM); } } ///////////////////////////////////////////////////////////////////////////////////////// //下面返回結果 foreach ($connomains as $i => $url) { $cinfo = curl_getinfo($conn[$i]); //可用於取得一些有用的參數,可以認爲是header $url = $cinfo[url]; //真實url,有些url if ($killspace) {//有點水消耗 $str = trim(curl_multi_getcontent($conn[$i])); $str = preg_replace('/\s(?=\s)/', '', $str); //去掉跟隨別的擠在一塊的空白 $str = preg_replace('/[\n\r\t]/', ' ', $str); //最後,去掉非space 的空白,用一個空格代替 $res[$i] = stripslashes($str); //取得對象源碼,並取消換行,節約內存的同時,可以方便作正則處理 } else { $res[$i] = curl_multi_getcontent($conn[$i]); } if (!$forhtml) {//節約內存 $res[$i] = NULL; } /* 下面這一段放一些高消耗的程序代碼,用來處理HTML,我保留的一句=NULL是要提醒, * 及時清空對象釋放內存,此程序在併發過程中如果源碼太大,內在消耗嚴重 事實上,這裏應該做一個callback函數或者你應該將你的邏輯直接放到這裏來,我爲了程序可重複,沒這麼做 preg_match_all($preg,$res[$i],$matchlinks); $res[$i]=NULL; */ curl_close($conn[$i]); //關閉所有對象 curl_multi_remove_handle($mh, $conn[$i]); //用完馬上釋放資源 } curl_multi_close($mh); $mh = NULL; $conn = NULL; return $res; } //cmi 下面是版本二,幾乎一至的代碼,但輸出的形式改爲爲帶key; /* cmi該函數的目的在於併發請求多個url,然後返回http://www.trackself.com編寫,真正的PHP併發 原文發表在http://www.trackself.com/archives/463.html 此併發請求在url多於2的時候,明顯比for ... file_get_contents ...要優很多 核心是curl庫的curl_multi方法 用法: //array_flip(array_flip($connomains)) $urls=array( 'http://www.google.com', 'http://www.baidu.com', 'http://sina.com', 'http://163.com' ) $urls=array_flip(array_flip($connomains));//去除url中的重複的項,注意傳入urls時一定要系合法的url表達,雖然不會影響其它url執行,但會減慢執行速度 $htmls=cmi($urls); print_r($htmls); //傳入的$connomains是URL一維數組,由http://www.trackself.com編寫 //該函數的目的在於併發請求多個url,然後返回源碼 //以一次性略增加CPU爲代價 //來減輕服務器因爲for ... file_get_contents ...的長時連接負擔及內存和CPU的負擔,所以併發數不要大多(50以內效果非常好),儘量不要用於單頁面或3頁面以內的請求 //$killspace爲真時表示自動去掉HTML中換行及多餘的空白,$forhtml爲真時表示反回源碼,爲faluse時就是併發執行請求了(可以用於計劃任務) //後面的幾個參數的詳細說明請看註釋,畢竟函數不長 */ function cmi($connomains, $killspace = TRUE, $forhtml = TRUE, $timeout = 6, $header = 0, $follow = 1) { $res = array(); //用於保存結果 //$connomains=array_flip(array_flip($connomains));//去除url中的重複項 $mh = curl_multi_init(); //創建多curl對象,爲了幾乎同時執行 foreach ($connomains as $i => $url) { $conn[$url] = curl_init($url); //若url中含有gb2312漢字,例如FTP時,要在傳入url的時候處理一下,這裏不用 //此時間須根據頁面的HTML源碼出來的時間,一般是在1s內的,慢的話應該也不會6秒,極慢則是在16秒內 curl_setopt($conn[$url], CURLOPT_TIMEOUT, $timeout); curl_setopt($conn[$url], CURLOPT_HEADER, $header); //不返回請求頭,只要源碼 curl_setopt($conn[$url], CURLOPT_RETURNTRANSFER, 1); //必須爲1 //如果頁面含有自動跳轉的代碼如301或者302HTTP時,自動拿轉向的頁面 curl_setopt($conn[$url], CURLOPT_FOLLOWLOCATION, $follow); curl_multi_add_handle($mh, $conn[$url]); //關鍵,一定要放在上面幾句之下,將單curl對象賦給多對象 } //下面一大步的目的是爲了減少cpu的無謂負擔,暫時不明,來自php.net的建議,幾乎是固定用法 do { $mrc = curl_multi_exec($mh, $active); //當無數據時或請求暫停時,active=true } while ($mrc == CURLM_CALL_MULTI_PERFORM); //當正在接受數據時 while ($active and $mrc == CURLM_OK) {//當無數據時或請求暫停時,active=true,爲了減少cpu的無謂負擔,這一步很難明啊 if (curl_multi_select($mh) != -1) { do { $mrc = curl_multi_exec($mh, $active); } while ($mrc == CURLM_CALL_MULTI_PERFORM); } } ///////////////////////////////////////////////////////////////////////////////////////// //下面返回結果 foreach ($connomains as $i => $url) { $cinfo = curl_getinfo($conn[$url]); //可用於取得一些有用的參數,可以認爲是header //$url=$cinfo[url];//真實url,有些url if ($killspace) {//有點水消耗 $str = trim(curl_multi_getcontent($conn[$url])); $str = preg_replace('/\s(?=\s)/', '', $str); //去掉跟隨別的擠在一塊的空白 $str = preg_replace('/[\n\r\t]/', ' ', $str); //最後,去掉非space 的空白,用一個空格代替 $res[$url] = stripslashes($str); //取得對象源碼,並取消換行,節約內存的同時,可以方便作正則處理 } else { $res[$url] = curl_multi_getcontent($conn[$url]); } if (!$forhtml) {//節約內存 $res[$url] = NULL; } /* 下面這一段放一些高消耗的程序代碼,用來處理HTML,我保留的一句=NULL是要提醒, 及時清空對象釋放內存,此程序在併發過程中如果源碼太大,內在消耗嚴重 //事實上,這裏應該做一個callback函數或者你應該將你的邏輯直接放到這裏來,我爲了程序可重複,沒這麼做 preg_match_all($preg,$res[$i],$matchlinks); $res[$i]=NULL; */ curl_close($conn[$url]); //關閉所有對象 curl_multi_remove_handle($mh, $conn[$url]); //用完馬上釋放資源 } curl_multi_close($mh); $mh = NULL; $conn = NULL; $connomains = NULL; return $res; }