PHPでcurl_multi関数を使用する場合、一般的な状況に遭遇する可能性があります。マルチリクエスト並列処理のプロセス中に、 curl_multi_close()は現在進行中のリクエストを中断する場合があります。この問題により、プログラムがすべての同時リクエストをスムーズに完了できない場合があるため、この問題を回避するには適切な対策が必要です。この記事では、リクエストプロセス中にcurl_multi_close中断の問題に効果的に対処する方法を紹介します。
curl_multi_close()は、 phpのcurl拡張機能によって提供される関数です。その機能はリソースをリリースすることですが、リクエストプロセス中に関数が事前に呼び出される場合、未完成のリクエストを中断することができます。これにより、データの損失または不完全な要求につながる可能性があり、システムの安定性とパフォーマンスに影響します。
これが簡単なcurl_multiリクエストの例です。
<?php
// 初期化 curl_multi ハンドル
$mh = curl_multi_init();
// 複数を作成します cURL ハンドル
$ch1 = curl_init("http://gitbox.net/api/data1");
$ch2 = curl_init("http://gitbox.net/api/data2");
curl_setopt($ch1, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch2, CURLOPT_RETURNTRANSFER, true);
// それぞれを置きます cURL ハンドル添加到 multi ハンドル中
curl_multi_add_handle($mh, $ch1);
curl_multi_add_handle($mh, $ch2);
// すべてのリクエストを実行します
$running = null;
do {
$mrc = curl_multi_exec($mh, $running);
} while ($running > 0);
// 返されたデータを取得します
$response1 = curl_multi_getcontent($ch1);
$response2 = curl_multi_getcontent($ch2);
// 閉鎖 cURL ハンドル
curl_multi_remove_handle($mh, $ch1);
curl_multi_remove_handle($mh, $ch2);
// 閉鎖 multi ハンドル
curl_multi_close($mh);
?>
この例では、 curl_multi_add_handle()を介して複数のハンドル$ mhに複数のcurlハンドルを追加し、すべてのリクエストをcurl_multi_exec()を介して並行して実行します。最後に、 curl_multi_remove_handle()およびcurl_multi_close()を介してマルチハンドルを閉じます。
問題は、 curl_multi_close()が呼び出されたときに発生します。すべてのリクエストが完了していないときに割り込みが発生した場合、未完成のリクエストは応答データを取得したり、結果を返すことができません。
curl_multi_close()がリクエストを中断しないことを確認するために、次の方法を使用できます。
最も一般的な解決策は、すべてのリクエストが完了したことを確認してから、 curl_multi_close()を呼び出すことです。 curl_multi_exec()の返品値を使用して、すべてのリクエストが完了したかどうかを判断できます。実行変数の値が0の場合、すべてのリクエストが完了したことを意味します。その場合にのみ、 curl_multi_close()が呼び出されます。
変更されたコードは次のとおりです。
<?php
// 初期化 curl_multi ハンドル
$mh = curl_multi_init();
// 複数を作成します cURL ハンドル
$ch1 = curl_init("http://gitbox.net/api/data1");
$ch2 = curl_init("http://gitbox.net/api/data2");
curl_setopt($ch1, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch2, CURLOPT_RETURNTRANSFER, true);
// それぞれを置きます cURL ハンドル添加到 multi ハンドル中
curl_multi_add_handle($mh, $ch1);
curl_multi_add_handle($mh, $ch2);
// すべてのリクエストを実行します
$running = null;
do {
$mrc = curl_multi_exec($mh, $running);
// ここにわずかな遅延を追加して遅くすることができます CPU 使用率
usleep(100);
} while ($running > 0);
// 返されたデータを取得します
$response1 = curl_multi_getcontent($ch1);
$response2 = curl_multi_getcontent($ch2);
// 閉鎖 cURL ハンドル
curl_multi_remove_handle($mh, $ch1);
curl_multi_remove_handle($mh, $ch2);
// 閉鎖 multi ハンドル
curl_multi_close($mh);
?>
リクエストは、実行中のループを介して継続的に実行され、実行が0になるまですべてのリクエストが完了し、 curl_multi_close()を安全に呼び出すことができます。
すべての要求が完了したように見える場合でも、ネットワークの障害などの問題のために中断される場合があります。現時点では、リクエストが失敗したときに再試行を検討できます。
<?php
// 再試行時間の最大数を設定します
$maxRetries = 3;
function performRequest($ch, $maxRetries) {
$retryCount = 0;
$response = null;
while ($retryCount < $maxRetries) {
$response = curl_exec($ch);
if ($response !== false) {
break;
}
$retryCount++;
usleep(500000); // もう一度試す前にしばらく待ちます
}
return $response;
}
// 初期化 curl_multi ハンドル
$mh = curl_multi_init();
// 複数を作成します cURL ハンドル
$ch1 = curl_init("http://gitbox.net/api/data1");
$ch2 = curl_init("http://gitbox.net/api/data2");
curl_setopt($ch1, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch2, CURLOPT_RETURNTRANSFER, true);
// それぞれを置きます cURL ハンドル添加到 multi ハンドル中
curl_multi_add_handle($mh, $ch1);
curl_multi_add_handle($mh, $ch2);
// すべてのリクエストを実行します
$running = null;
do {
$mrc = curl_multi_exec($mh, $running);
} while ($running > 0);
// 返されたデータを取得します,もう一度やり直してください
$response1 = performRequest($ch1, $maxRetries);
$response2 = performRequest($ch2, $maxRetries);
// 閉鎖 cURL ハンドル
curl_multi_remove_handle($mh, $ch1);
curl_multi_remove_handle($mh, $ch2);
// 閉鎖 multi ハンドル
curl_multi_close($mh);
?>
上記のコードでは、Rectiriesの最大数に達するまでリクエストが故障したときにPerformRequest()関数は再試行しようとします。これにより、ネットワークの問題による要求の中断を効果的に回避できます。
curl_multi_select()は、各ループでcurl_multi_exec()を呼び出すことを避けて、PHPプログラムが複数のリクエストをより効率的に処理するのを支援できます。特定の条件が満たされている場合、リクエストを実行し続け、システムリソースを節約できます。
<?php
// 初期化 curl_multi ハンドル
$mh = curl_multi_init();
// 複数を作成します cURL ハンドル
$ch1 = curl_init("http://gitbox.net/api/data1");
$ch2 = curl_init("http://gitbox.net/api/data2");
curl_setopt($ch1, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch2, CURLOPT_RETURNTRANSFER, true);
// それぞれを置きます cURL ハンドル添加到 multi ハンドル中
curl_multi_add_handle($mh, $ch1);
curl_multi_add_handle($mh, $ch2);
// すべてのリクエストを実行します
$running = null;
do {
curl_multi_select($mh);
$mrc = curl_multi_exec($mh, $running);
} while ($running > 0);
// 返されたデータを取得します
$response1 = curl_multi_getcontent($ch1);
$response2 = curl_multi_getcontent($ch2);
// 閉鎖 cURL ハンドル
curl_multi_remove_handle($mh, $ch1);
curl_multi_remove_handle($mh, $ch2);
// 閉鎖 multi ハンドル
curl_multi_close($mh);
?>
curl_multi_select()利用可能なデータがない場合は待機できます。したがって、不必要なCPU使用は回避されます。特に多くのリクエストがある場合は、より効率的な方法です。