PHPのcurl_multiを使って少しでもパフォーマンス改善を図りたい

2月 7, 2016

≪≪この記事をすべて読むには約 5 分かかります≫≫

複数サイトからPHPでXMLやJSON形式のレスポンスを取得するサイトを作っています。

PHPは基本的にシングルスレッドで働くサーバーサイド言語なので、マルチタスクが出来ません。

PHPの「マルチタスク」

シングルスレッドだからこそ、プログラムがわかりやすく初心者の私にもなんとかなるという面もあります。が、ページを表示するために複数のサーバーからデータを受け取るようにしていると、ユーザーを長く待たせる事になってしまいます。

有効な方法の一つはキャッシュを作っておくことですが、キャッシュできないデータもあるわけで、少しでも他サイトへのリクエスト、ページの表示を早くするためにはやはりマルチタスク化が欠かせません。

シングルスレッドの言語とはいえ、PHPで「マルチタスク」を実現する方法がいくつか実装されています。

マルチタスク

pthreads

pthreadsという拡張機能を入れればできる(擬似的に?)のですが、レンタルサーバーを使っている私のサーバーには入っていません。(使うことはできるかもしれませんが、帯域制限を受けそうな気がします)

ignore_user_abort

別の選択肢は、ignore_user_abortという関数を中心にした設定をして、ユーザーに表示される表示を出力し終わってからもPHPを実行し続けるという方法です。

ネットを検索すると幾つかコード例が出てきます。

<?php
ignore_user_abort(true);
set_time_limit(0);

$strURL = "PUT YOUR REDIRCT HERE";
header("Location: $strURL", true);
header("Connection: close", true);
header("Content-Encoding: none\r\n");
header("Content-Length: 0", true);

flush();
ob_flush();

session_write_close();

// Continue processing...

sleep(100);
exit;
?>

by mheumann

が、WordPressやJoomlaといったCMSとは相性が良くない(WordPressでは無効化されているはずです)です。有効になっていたら、色々問題が出そうですし。

curl_multi

最後の、一番消極的な選択肢がcurl_multiを使う方法です。HTTPリクエストを同時進行させてデータを早く受け取る事ができるようになります。

コードを書き換えるのに少し手間がかかりますが、リクエスト数をもう少し増やしたいので、文句を言っていられません。

使い方は

  1. curlのハンドラは普通に作る
  2. multi_curl用のハンドラを別に作る
  3. curl用のハンドラをmulti_curlに渡して同時実行をさせる
  4. multi_curl_execは読み込みが終わる前に制御を戻すので、状態変数を見ながら終わるのを待つ
  5. 終わったら(終わらなくても処理はできる・・・)読み込まれた結果を使う

という流れです。

実際にやってみたのですが、体感速度は変わらないか、むしろ遅くなったような気すらします。主な理由はクライアント(私)のインターネット環境のせいだと信じていますが、極端に読み込まれるファイルの大きさに違いがあると遅くなる可能性があるのは理に適っています。

PHPのサイトを見ると、コネクションが10個以上になってきたら、すべて終わるのを待たずに処理を始めた方が良いという書き込みがありました。もう少し勉強が必要なようです。

基本的に一部のソースを除いて同時接続しないようにキャッシュの有効時間をずらしているので、そんなに有効ではないのかもしれません。(例外がAmazon Product Advertising APIなのですが、結構厄介です・・・)