2010-11-22 3 views
0

J'utilise cURL dans mon application PHP pour me connecter à une API RESTful. Cependant, j'ai récemment découvert que je ne suis pas en train de paralléliser mes connexions cURL et que l'exécution de plusieurs connexions successives entraîne une latence extrême pour l'utilisateur final.Comment refactoriser ce script cURL pour tirer parti de la fonction curl_multi de PHP?

Je n'ai pas utilisé curl_multi avant et je suis un peu à perte après avoir lu la documentation. Comment puis-je refactoriser le code suivant pour profiter de la parallélisation de curl_multi?

EDIT: J'ai oublié de mentionner que j'ai ouvert l'API qui est utilisée ici. Ce sont mes propres Directed Edge PHP bindings. Donc, si vous le souhaitez, vous pouvez également avoir votre aide ici fusionnée dans le code sur GitHub et vous serez listé comme un contributeur.

Voici un exemple de ce que je fais dans le code client:

// 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); 

Et voici les fonctions pertinentes de 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; 
    } 

Répondre

1

Je ne connaissais pas curl_multi avant votre question , c'est une interface assez bizarre (pour PHP).

On dirait qu'il ya une 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); 

Je commencerai par cela.

+0

' curl_multi' est une interface bizarre, ou mon code est? –

+0

curl_multi est bizarre, pas votre code. –

+0

Rgr. J'ai vu votre montage un peu trop tard. –

0

Dans le cas où quelqu'un est intéressé, voici comment j'ai refacturé le code pour faire usage de curl_multi. Et s'il vous plaît, contribute to the bindings si tout cela semble cool, ou si vous pouvez faire un meilleur travail! `Curl_multi` est une interface bizarre, ou mon code est?

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" 
    } 
} 
Questions connexes