2010-11-22 30 views
0

我在我的PHP應用程序中使用cURL來連接到RESTful API。不過,我最近才發現,我並沒有對cURL連接進行並行化處理,因此對最終用戶執行幾次連續的連接導致極度延遲。如何重構此cURL腳本以利用PHP的curl_multi函數?

我以前沒有使用過curl_multi,在閱讀文檔後我感到很茫然。如何最好地重構以下代碼以利用curl_multi的並行化?

編輯:我忘了提到我開源了這裏使用的API。這些是我自己的Directed Edge PHP bindings。所以如果你願意,你也可以在這裏把你的幫助合併到GitHub上的代碼中,你將被列爲貢獻者。

下面是我在做什麼客戶端代碼的例子:

// Get 100 goal recommendations from Directed Edge 
    $de = new DirectedEdgeRest(); 
    $item = "user".$uid; 
    $limit = 100; 
    $tags = "goal"; 
    $recommendedGoals = $de->getRecommended($item, $tags, $limit); 

    // Get 100 interest recommendations from Directed Edge 
    $de = new DirectedEdgeRest(); 
    $item = "user".$uid; 
    $limit = 100; 
    $tags = "interest"; 
    $recommendedInterests = $de->getRecommended($item, $tags, $limit); 

而且這裏距離DirectedEdgeRest()

/** 
    * Returns array of recommended result IDs for an item 
    * @param string $item Item, e.g. "Miles%20Davis" 
    * @param string $tags Tags as comma delimited string, e.g. "product,page" 
    * @param int $limit Limit for max results 
    * 
    * @return array Recommended result IDs 
    */ 
    public function getRecommended($item, $tags, $limit) 
    { 
    // Connect to Directed Edge and parse the returned XML 
    $targeturl = self::buildURL($item, 'recommended', $tags, $limit, 'true'); 
    $response = self::getCurlResponse($targeturl); 
    $xml = self::parseXML($response); 

    // Iterate through the XML and place IDs into an array 
    foreach($xml->item->recommended as $recommended) { 
     $recommendedResults[] = filter_var($recommended, FILTER_SANITIZE_NUMBER_INT); 
    } 

    return $recommendedResults; 
    } 

    /** 
    * Builds URL for cURL 
    * @param string $item Item, e.g. "Miles%20Davis" 
    * @param string $type Type of API request: either "related" or "recommended" 
    * @param string $tags Tags as comma delimited string, e.g. "product,page" 
    * @param int $limit Limit for max results 
    * @param string $exclude "true" if you want to exclude linked, "false" otherwise 
    * 
    * @return string The target URL 
    */ 
    private function buildURL($item, $type, $tags, $limit, $exclude) 
    { 
    $targeturl = DE_BASE_URL; 
    $targeturl .= $item; // Item 
    $targeturl .= "/" . $type; // Type 
    $targeturl .= "?tags=" . $tags; // Tags 
    $targeturl .= "&maxresults=" . $limit; // Limit 
    $targeturl .= "&excludeLinked=" . $exclude; // Exclude 
    return $targeturl; 
    } 

    /** 
    * Returns the cURL response given a target URL 
    * @param string $targeturl The target URL for cURL 
    * 
    * @return string cURL Response 
    */ 
    private function getCurlResponse($targeturl) 
    { 
    $ch = curl_init($targeturl); 
    curl_setopt($ch, CURLOPT_POST, FALSE); 
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); 
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); 
    $response = curl_exec($ch); 
    curl_close($ch); 
    return $response; 
    } 

回答

1

相關功能我不知道的curl_multi你的問題之前, ,這是一個非常奇怪的(用於PHP)界面。

它看起來像有一個Hello World example in the curl_multi_init documentation

// create both cURL resources 
$ch1 = curl_init(); 
$ch2 = curl_init(); 

// set URL and other appropriate options 
curl_setopt($ch1, CURLOPT_URL, "http://www.example.com/"); 
curl_setopt($ch1, CURLOPT_HEADER, 0); 
curl_setopt($ch2, CURLOPT_URL, "http://www.php.net/"); 
curl_setopt($ch2, CURLOPT_HEADER, 0); 

//create the multiple cURL handle 
$mh = curl_multi_init(); 

//add the two handles 
curl_multi_add_handle($mh,$ch1); 
curl_multi_add_handle($mh,$ch2); 

$running=null; 
//execute the handles 
do { 
    usleep(10000); 
    curl_multi_exec($mh,$running); 
} while ($running > 0); 

//close the handles 
curl_multi_remove_handle($mh, $ch1); 
curl_multi_remove_handle($mh, $ch2); 
curl_multi_close($mh); 

我會着手行動。

+0

'curl_multi'是一個奇怪的界面,或者我的代碼是? – 2010-11-22 06:09:25

+0

curl_multi是離奇的,而不是你的代碼。 – 2010-11-22 06:21:00

+0

Rgr。我看到你的編輯有點太晚了。 – 2010-11-22 06:34:46

0

如果有人感興趣,下面是我如何重構使用curl_multi的代碼。如果這一切看起來很酷,或者如果你能做得更好,請給予contribute to the bindings

class DirectedEdgeRest 
{ 
    /** 
    * Gets multiple simultaneous recommendations from Directed Edge 
    * @param array $queryArray Array of the form array(0 => (array('item' => (string) $item, 'tags' => (string) $tags, 'limit' => (int) $limit)) 
    * 
    * @return array Multi-dimensional array containing responses to 
    * queries in the order they were passed in the array 
    */ 
    public function getMultiRecommended($queryArray) 
    { 
    $targetUrls = array(); 

    foreach($queryArray as $query) { 
     $targeturl = self::buildURL($query['item'], 'recommended', $query['tags'], $query['limit'], 'true'); 
     $targetUrls[] = $targeturl; 
    } 

    $responses = self::getMultiCurlResponses($targetUrls); 

    $xmlArray = array(); 

    foreach($responses as $response) { 
     $xmlArray[] = self::parseXML($response);  
    } 

    $count = count($xmlArray); 

    // Iterate through the XML and place IDs into an array 
    for($i = 0; $i < $count; $i++) {    
     foreach($xmlArray[$i]->item->recommended as $recommended) { 
     $recommendedResults[$i][] = filter_var($recommended, FILTER_SANITIZE_NUMBER_INT); 
     } 
    } 

    return $recommendedResults; 
    } 

    /** 
    * Returns the cURL responses given multiple target URLs 
    * @param array $targetUrls Array of target URLs for cURL 
    * 
    * @return array cURL Responses 
    */ 
    private function getMultiCurlResponses($targetUrls) 
    { 
    // Cache the count 
    $count = count($targetUrls); 

    // Create the multiple cURL handles 
    for($i = 0; $i < $count; $i++) { 
     $ch[$i] = curl_init($targetUrls[$i]); 
     curl_setopt($ch[$i], CURLOPT_POST, FALSE); 
     curl_setopt($ch[$i], CURLOPT_SSL_VERIFYPEER, FALSE); 
     curl_setopt($ch[$i], CURLOPT_RETURNTRANSFER, TRUE); 
    } 

    // Initialize the multiple cURL handle 
    $mh = curl_multi_init(); 

    // Add the handles to the curl_multi handle 
    for($i = 0; $i < $count; $i++) { 
     curl_multi_add_handle($mh, $ch[$i]); 
    } 

    $running=null; 
    // Execute the handles 
    do { 
     curl_multi_exec($mh,$running); 
    } while ($running > 0); 

    $responses = array(); 

    // Remove the handles and return the response 
    for($i = 0; $i < $count; $i++) { 
     curl_multi_remove_handle($mh, $ch[$i]); 

     $responses[$i] = curl_multi_getcontent($ch[$i]); 
    } 

    // Close the multiple cURL handle 
    curl_multi_close($mh); 

    return $responses; 
    } 
} 

$uid = 3; 
$de = new DirectedEdgeRest(); 
$query['item'] = "user".$uid; 
$query['limit'] = 10; 
$query['tags'] = "goal"; 
$queryArray[0] = $query; 

$query['tags'] = "question"; 
$queryArray[1] = $query; 


$recommended = $de->getMultiRecommended($queryArray); 
echo '<pre>'; 
var_dump($recommended); 

// Outputs... 
array(2) { 
    [0]=> 
    array(10) { 
    [0]=> 
    string(3) "141" 
    [1]=> 
    string(2) "64" 
    [2]=> 
    string(2) "37" 
    [3]=> 
    string(2) "65" 
    [4]=> 
    string(2) "63" 
    [5]=> 
    string(1) "7" 
    [6]=> 
    string(2) "78" 
    [7]=> 
    string(1) "9" 
    [8]=> 
    string(2) "30" 
    [9]=> 
    string(2) "10" 
    } 
    [1]=> 
    array(10) { 
    [0]=> 
    string(2) "97" 
    [1]=> 
    string(3) "125" 
    [2]=> 
    string(3) "133" 
    [3]=> 
    string(3) "127" 
    [4]=> 
    string(3) "101" 
    [5]=> 
    string(3) "134" 
    [6]=> 
    string(2) "69" 
    [7]=> 
    string(2) "80" 
    [8]=> 
    string(2) "19" 
    [9]=> 
    string(3) "129" 
    } 
}