PHPでは、外部API、Webサイト、またはサービスでネットワークリクエストを行う必要があることがよくあります。通常のcurl_exec()シングルリクエストは単純ですが、同時性の高いシナリオでは、そのパフォーマンスボトルネックは非常に明白です。各リクエストは順次実行され、前のリクエストが次のリクエストの前に完了するのを待って、全体的な時間が直線的に増加します。
ネットワークリクエスト効率を改善するために、PHPは2つの非常に強力なツールを提供します: curl_share_init()とcurl_multi_*シリーズ関数。この記事では、高性能の同時リクエストを実現するためにそれらを使用する方法を詳細に検討します。
curl_share_init()は、DNSキャッシュ、Cookie、SSLセッションなど、複数のCurlハンドル間でデータを共有するために使用されます。
たとえば、同じドメイン名の複数のアドレスを同時に要求する必要がある場合、共有DNSキャッシュを有効にすると、DNSクエリ時間を大幅に短縮できます。
$sh = curl_share_init();
curl_share_setopt($sh, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS);
このコードは共有ハンドルを初期化し、DNSデータを共有するように設定されています。次に、この共有ハンドルを各カールリクエストにバインドします。
curl_multi_*一連の関数を使用すると、 curl_exec()のように1つずつ送信するのではなく、複数のHTTP要求を同時に開始できます。
主な機能には次のものが含まれます。
curl_multi_init() :マルチハンドルを初期化します。
curl_multi_add_handle() :マルチハンドルに単一のカールハンドルを追加します。
curl_multi_exec() :マルチハンドルですべてのリクエストを実行します。
curl_multi_select() :アクティブを待っている接続をブロックします。
curl_multi_getContent() :各リクエストの返されたコンテンツを取得します。
curl_multi_remove_handle() :終了したら、単一のハンドルを削除します。
curl_multi_close() :マルチハンドルを閉じます。
Curl_share_init()およびcurl_multi_*シリーズ機能を使用して複数のアドレスを同時に要求する方法を示す完全な例を示します。
<?php
// 要求する URL リスト
$urls = [
'https://m66.net/api/endpoint1',
'https://m66.net/api/endpoint2',
'https://m66.net/api/endpoint3'
];
// 共有ハンドルを初期化します
$sh = curl_share_init();
curl_share_setopt($sh, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS);
// 初期化 multi ハンドル
$mh = curl_multi_init();
$curl_handles = [];
// それぞれのため URL 別のものを作成します curl ハンドル
foreach ($urls as $i => $url) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SHARE, $sh); // 绑定共享ハンドル
curl_multi_add_handle($mh, $ch);
$curl_handles[$i] = $ch;
}
// すべてのリクエストを実行します
$running = null;
do {
$status = curl_multi_exec($mh, $running);
if ($status > 0) {
echo "cURL error: " . curl_multi_strerror($status) . "\n";
}
// アクティブな接続を待っています
curl_multi_select($mh);
} while ($running > 0);
// 結果を取得します
$responses = [];
foreach ($curl_handles as $i => $ch) {
$responses[$i] = curl_multi_getcontent($ch);
curl_multi_remove_handle($mh, $ch);
curl_close($ch);
}
// 閉鎖 multi そして share ハンドル
curl_multi_close($mh);
curl_share_close($sh);
// 出力結果
foreach ($responses as $i => $response) {
echo "Response from URL $i:\n$response\n\n";
}
?>
curl_multi_*を使用すると、すべてのリクエストが可能な限り同時に実行され、全体の時間は合計ではなく最長の単一リクエストに近いものになります。
curl_share_init()を使用すると、重複したDNSクエリ、SSLハンドシェイクなどのオーバーヘッドを減らし、パフォーマンスをさらに最適化できます。
同じドメイン名API(同時に複数のインターフェイスをクロールする、バッチでWebページをrawう、複数のマイクロサービスデータの同期など)の高い並行性と頻繁な要求があるシナリオでは、この組み合わせは効率を大幅に改善できます。
DNS共有は常に大幅に高速化するとは限りません。主に同じドメイン名と複数のリクエストで有効になります。
合理的に設定されたタイムアウト:同時に立ち往生した要求が全体的な状況に影響する場合があります。
並行性の数を制御する:リクエストが多すぎると、サーバーまたはローカルリソースが使い果たされ、セマフォまたはバッチで配布される可能性があります。
エラー処理:例では、単一の要求の処理が詳細に処理できず、実際のアプリケーションを補充する必要があります。