phpでapiを使うなら必須なcurl_multi

curl_multiというのを見つけたので使ってみました. 外部APIを使う人にとっては必須かもしれません.

curl_multiとは

そのまんま,curlを複数並列に走らせるための関数です. 直列にすると待機時間が長いので,並列にリクエストを投げることで高速化が見込めます. php5から使えるようです.

基本的な使い方

使い方としては次の通り.

  1. それぞれのリクエスト用のcurlを作成する
  2. curl_multiを一つ作り,そこにそれぞれのリクエスト用のcurlをセットする
  3. 実行!&リクエスト終了待ち
  4. それぞれのリクエスト用curl,curl_multiの両方をcloseする

php関数リファレンスよりサンプルコード

1
<?php // cURL リソースを作成します $ch1 = curl_init(); $ch2 = curl_init(); // URL およびその他適切なオプションを設定します。 curl_setopt($ch1, CURLOPT_URL, "http://lxr.php.net/"); curl_setopt($ch1, CURLOPT_HEADER, 0); curl_setopt($ch2, CURLOPT_URL, "http://www.php.net/"); curl_setopt($ch2, CURLOPT_HEADER, 0); // マルチ cURL ハンドルを作成します $mh = curl_multi_init(); // ふたつのハンドルを追加します curl_multi_add_handle($mh,$ch1); curl_multi_add_handle($mh,$ch2); $active = null; // ハンドルを実行します do { $mrc = curl_multi_exec($mh, $active); } while ($mrc == CURLM_CALL_MULTI_PERFORM); while ($active && $mrc == CURLM_OK) { if (curl_multi_select($mh) != -1) { do { $mrc = curl_multi_exec($mh, $active); } while ($mrc == CURLM_CALL_MULTI_PERFORM); } } // ハンドルを閉じます curl_multi_remove_handle($mh, $ch1); curl_multi_remove_handle($mh, $ch2); curl_multi_close($mh); ?>

ですが,こんなの面倒なので,ひとまとまりに関数化してしまいましょう

お手軽curl_multi

関数にまとめました. arrayでurlを指定し,arrayでデータが返ってきます. 自分の環境ではなぜかよく失敗するので,失敗したurlをarrayで返すようにもしました.

1
public function fetchMultiUrl($urls, $timeout = 0, &$errorUrls = array()) { $mh = curl_multi_init(); foreach ($urls as $key => $url) { $conn[$key] = curl_init($url); curl_setopt($conn[$key], CURLOPT_RETURNTRANSFER, 1); curl_setopt($conn[$key], CURLOPT_FAILONERROR, 1); curl_setopt($conn[$key], CURLOPT_FOLLOWLOCATION, 1); curl_setopt($conn[$key], CURLOPT_MAXREDIRS, 3); if ($timeout) { curl_setopt($conn[$key], CURLOPT_TIMEOUT, $timeout); } curl_multi_add_handle($mh, $conn[$key]); } $active = null; do { $mrc = curl_multi_exec($mh, $active); } while ($mrc == CURLM_CALL_MULTI_PERFORM); while ($active and $mrc == CURLM_OK) { if (curl_multi_select($mh) != -1) { do { $mrc = curl_multi_exec($mh, $active); } while ($mrc == CURLM_CALL_MULTI_PERFORM); } } //データを取得 $res = array(); foreach ($urls as $key => $url) { if (($err = curl_error($conn[$key])) == '') { $res[$key] = curl_multi_getcontent($conn[$key]); } else { $errorUrls[$key] = $url_list[$key]; } curl_multi_remove_handle($mh, $conn[$key]); curl_close($conn[$key]); } curl_multi_close($mh); return $res; }

実際に使ったところ,30アクセスで40秒ぐらいだったのが10秒ぐらいまで高速化できました. それほど難しくないですし,連続してAPIをたたく場合は便利です!