php實現併發處理之curl篇

php在併發處理方面的確不如java好。可是也有一些方法能夠實現併發處理。好比使用curl就能夠實現url的併發請求。php


看到網上有人說使用curl會致使阻塞,即全部的請求數據都獲取完畢後一併返回,而後再進行數據處理。而不是獲取一個請求的數據就處理一個數據。其實這種說法是不對的,只能說明他在代碼實現上有問題。java


在php官方找了段致使阻塞的示例代碼,以下:node


function multiple_threads_request($nodes){ 併發

        $mh = curl_multi_init(); curl

        $curl_array = array(); 函數

        foreach($nodes as $i => $url) url

        { spa

            $curl_array[$i] = curl_init($url); .net

            curl_setopt($curl_array[$i], CURLOPT_RETURNTRANSFER, true); code

            curl_multi_add_handle($mh, $curl_array[$i]); 

        } 

        $running = NULL; 

        do { 

            usleep(10000); 

            curl_multi_exec($mh,$running); 

        } while($running > 0); 

          

        $res = array(); 

        foreach($nodes as $i => $url) 

        { 

            $res[$url] = curl_multi_getcontent($curl_array[$i]); 

        } 

          

        foreach($nodes as $i => $url){ 

            curl_multi_remove_handle($mh, $curl_array[$i]); 

        } 

        curl_multi_close($mh);        

        return $res; 

print_r(muti_thread_request(array( 

    'http://www.example.com', 

    'http://www.example.net', 

)));


下面是邊請求url,邊處理返回數據的示例代碼:


/*

 * @purpose : 使用curl並行處理url

 * @return : array 每一個url獲取的數據

 * @param : $urls array url列表

 * @param : $callback string 須要進行內容處理的回調函數。示例:func(array)

 */

function curl($urls = array(), $callback = '')

{

    $response = array();

    if (empty($urls)) {

        return $response;

    }

    $chs = curl_multi_init();

    $map = array();

    foreach($urls as $url){

        $ch = curl_init();

        curl_setopt($ch, CURLOPT_URL, $url);

        curl_setopt($ch, CURLOPT_TIMEOUT, 1);

        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

        curl_setopt($ch, CURLOPT_HEADER, 0);

        curl_setopt($ch, CURLOPT_NOSIGNAL, true);

        curl_multi_add_handle($chs, $ch);

        $map[strval($ch)] = $url;

    }

    do{

        if (($status = curl_multi_exec($chs, $active)) != CURLM_CALL_MULTI_PERFORM) {

            if ($status != CURLM_OK) { break; } //若是沒有準備就緒,就再次調用curl_multi_exec

            while ($done = curl_multi_info_read($chs)) {

                $info = curl_getinfo($done["handle"]);

                $error = curl_error($done["handle"]);

                $result = curl_multi_getcontent($done["handle"]);

                $url = $map[strval($done["handle"])];

                $rtn = compact('info', 'error', 'result', 'url');

                if (trim($callback)) {

                    $callback($rtn);

                }

                $response[$url] = $rtn;

                curl_multi_remove_handle($chs, $done['handle']);

                curl_close($done['handle']);

                //若是仍然有未處理完畢的句柄,那麼就select

                if ($active > 0) {

                    curl_multi_select($chs, 0.5); //此處會致使阻塞大概0.5秒。

                }

            }

        }

    }

    while($active > 0); //還有句柄處理還在進行中

    curl_multi_close($chs);

    return $response;

}

  

//使用方法

function deal($data){

    if ($data["error"] == '') {

        echo $data["url"]." -- ".$data["info"]["http_code"]."\n";

    } else {

        echo $data["url"]." -- ".$data["error"]."\n";

    }

}

$urls = array();

for ($i = 0; $i < 10; $i++) {

    $urls[] = 'http://www.baidu.com/s?wd=etao_'.$i;

    $urls[] = 'http://www.so.com/s?q=etao_'.$i;

    $urls[] = 'http://www.soso.com/q?w=etao_'.$i;

}

curl($urls, "deal");

 


註釋:

1.關於curl_multi_exec函數的返回值:


返回CURLM_CALL_MULTI_PERFORM 說明curl_multi_exec須要立刻被再調用一次。

返回CURLM_OK 說明已經有須要處理的數據。這時你須要進行相關處理,處理完後再次調用curl_multi_exec。

php中的curl_multi_exec是調用的curl庫中的curl_multi_perform方法。代碼在multi.c的230行左右。


2.此方式,雖然在獲取數據和數據處理上是並行的,可是在數據處理時依然是串行的。即數據是一條條依次處理的。若是deal方法比較耗時的話,那總體會很是耗時。

相關文章
相關標籤/搜索