2010-11-22 68 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" 
    } 
}