質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Q&A

解決済

1回答

7831閲覧

curl_multiによる並列処理について

pgnoobdesu

総合スコア35

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

0グッド

1クリップ

投稿2016/02/20 16:20

以下のコードの引用元のサイト(http://qiita.com/Hiraku/items/1c67b51040246efb4254)を見て色々とテストしようとしてるのですがよくわかりません。

PHP

1/* 2 * 2) リクエストを開始する 3 * - curl_multiでは即座に制御が戻る(レスポンスが返ってくるのを待たない) 4 * - いきなり失敗するケースを考えてエラー処理を書いておく 5 * - do~whileはlibcurl<7.20で必要 6 */ 7do { 8 $stat = curl_multi_exec($mh, $running); //multiリクエストスタート 9} while ($stat === CURLM_CALL_MULTI_PERFORM); 10if ( ! $running || $stat !== CURLM_OK) { 11 throw new RuntimeException('リクエストが開始出来なかった。マルチリクエスト内のどれか、URLの設定がおかしいのでは?'); 12} 13 14/* 15 * 3) レスポンスをcurl_multi_selectで待つ 16 * - 何かイベントがあったらループが進む 17 * selectはイベントが起きるまでCPUをほとんど消費せずsleep状態になる 18 * - どれか一つレスポンスが返ってきたらselectがsleepを中断して何か数字を返す。 19 * 20 */ 21do switch (curl_multi_select($mh, $TIMEOUT)) { //イベントが発生するまでブロック 22 // 最悪$TIMEOUT秒待ち続ける。 23 // あえて早めにtimeoutさせると、レスポンスを待った状態のまま別の処理を挟めるようになります。 24 // もう一度curl_multi_selectを繰り返すと、またイベントがあるまでブロックして待ちます。 25 26 case -1: //selectに失敗。ありうるらしい。 https://bugs.php.net/bug.php?id=61141 27 usleep(10); //ちょっと待ってからretry。ここも別の処理を挟んでもよい。 28 do { 29 $stat = curl_multi_exec($mh, $running); 30 } while ($stat === CURLM_CALL_MULTI_PERFORM); 31 continue 2; 32 33 case 0: //タイムアウト -> 必要に応じてエラー処理に入るべきかも。 34 continue 2; //ここではcontinueでリトライします。 35 36 default: //どれかが成功 or 失敗した 37 do { 38 $stat = curl_multi_exec($mh, $running); //ステータスを更新 39 } while ($stat === CURLM_CALL_MULTI_PERFORM); 40 41 do if ($raised = curl_multi_info_read($mh, $remains)) { 42 //変化のあったcurlハンドラを取得する 43 $info = curl_getinfo($raised['handle']); 44 echo "$info[url]: $info[http_code]\n"; 45 $response = curl_multi_getcontent($raised['handle']); 46 47 if ($response === false) { 48 //エラー。404などが返ってきている 49 echo 'ERROR!!!', PHP_EOL; 50 } else { 51 //正常にレスポンス取得 52 echo $response, PHP_EOL; 53 } 54 curl_multi_remove_handle($mh, $raised['handle']); 55 curl_close($raised['handle']); 56 } while ($remains); 57 //select前に全ての処理が終わっていたりすると 58 //複数の結果が入っていることがあるのでループが必要 59 60} while ($running); 61echo 'finished', PHP_EOL; 62curl_multi_close($mh);

まず、curl_multi_execの関数の意味がよくわかりません。
リクエストを開始するときにも呼んでるし、イベントが発生した時にも呼んでいます。
リクエスト開始したら後は待って受信するだけだと思うんですが、何で複数回呼ぶ必要があるんでしょうか?
リクエスト開始するためだけの関数じゃないんでしょうか?

また、CURLM_CALL_MULTI_PERFORMの定数の意味もわからないので教えてほしいです。
CURLM_CALL_MULTI_PERFORMを返さなくなったということは何を意味するんでしょうか?
これを返さなくなったらそのまま後続の処理を実行してますが、$statにエラーが返ってないかを確認しなくていいのでしょうか?

とりあえずまずこれらの質問にご回答よろしくお願い致します。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

まず、curl_multi_execの関数の意味がよくわかりません。

見た感じ curl_multi_execcurl_multi_perform のラッパーです。

https://github.com/ngyuki/php-src/blob/b0f0211b1ae695809f72a8a241649cda6ecd38bb/ext/curl/multi.c#L194-L227

リクエストを開始するときにも呼んでるし、イベントが発生した時にも呼んでいます。
リクエスト開始したら後は待って受信するだけだと思うんですが、何で複数回呼ぶ必要があるんでしょうか?
リクエスト開始するためだけの関数じゃないんでしょうか?

curl_multi_perform はリクエストの書き込み(送信)や、レスポンスの読み込み(受信)のために繰り返し呼ぶ必要があります。

リクエストを開始した後、リクエストの内容をサーバに送信したり、レスポンスをサーバから受信したりする処理が必要です。待っているだけでそれらの処理が勝手に行われることはありません。リクエストの開始時に新しくスレッドを開始してそのスレッドでリクエスト/レスポンスの I/O(送信/受信) をするのであれば別ですけど、libcurl(PHP の curl 関数で使用されているライブラリ)の実装はそのようになっていない、ということだと思います。

また、CURLM_CALL_MULTI_PERFORMの定数の意味もわからないので教えてほしいです。
CURLM_CALL_MULTI_PERFORMを返さなくなったということは何を意味するんでしょうか?

その定数の意味自体はよくわかりませんでしたが man 3 curl_multi_perform によると、

If you receive CURLM_CALL_MULTI_PERFORM, this basically means that you should call curl_multi_perform again, before you select() on more actions

その値が返されたときは、select などを行う前にもう一度 curl_multi_perform を呼ばなければならない、とのことです。

これを返さなくなったらそのまま後続の処理を実行してますが、$statにエラーが返ってないかを確認しなくていいのでしょうか?

php

1if ( ! $running || $stat !== CURLM_OK) {

でにエラーが確認されているのではないでしょうか。

投稿2016/02/21 04:43

ngyuki

総合スコア4514

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

pgnoobdesu

2016/02/21 07:02

確かにリクエスト開始時はそこでエラー確認しているんですが、後半のdo switch文内ではcurl_multi_execを実行した後は、while文の $stat === CURLM_CALL_MULTI_PERFORM  でしかチェックしてないんですよね。 なので、CURLM_CALL_MULTI_PERFORMを返さなくなるということはエラーがないとうことでいいのかと思ったのですが、そんなはずないよなぁとも思います。 でも大分理解できました。回答ありがとうございました。
ngyuki

2016/02/22 00:03

> 後半のdo switch文内ではcurl_multi_execを実行した後は、while文の $stat === CURLM_CALL_MULTI_PERFORM でしかチェックしてないんですよね。 確かにそのとおりですね。`man 3 curl_multi_perform` を見た感じそこでも `CURLM_OK` を確認した方が良いような気もします。 が、そのタイミングで `CURLM_OK` でも `CURLM_CALL_MULTI_PERFORM` でも無い値が返ってきても、その後どうしたら良いかが良くわからないですね。。。 (マルチリクエスト全体をエラーにするべきなのか `curl_multi_select` からやり直して良いのか)
pgnoobdesu

2016/02/23 01:30

今後、他の方の回答は見込めないので、ngyukiさんをBAとします。ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問