0

我在我的 PHP 应用程序中使用 cURL 连接到 RESTful API。但是,我最近才发现我没有并行化我的 cURL 连接,因此执行几个连续的连接会导致最终用户出现极端延迟。

我以前没有使用curl_multi过,在阅读文档后我有点不知所措。如何最好地重构以下代码以利用curl_multi的并行化?

编辑:我忘了提到我开源了这里使用的 API。这些是我自己的Directed Edge PHP 绑定。因此,如果您愿意,也可以将您的帮助合并到 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;
  }
4

2 回答 2

1

在您提出问题之前我不知道curl_multi,这是一个非常奇怪的(对于 PHP)界面。

看起来curl_multi_init 文档中有一个 Hello World 示例

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

我会从那开始。

于 2010-11-22T06:08:14.290 回答
0

如果有人感兴趣,这里是我如何重构代码以使用curl_multi. 如果这一切看起来很酷,或者您可以做得更好,请为绑定做出贡献!

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"
  }
}
于 2010-11-22T08:43:26.643 回答