When using the curl_multi_* series of functions to make concurrent requests, we usually open multiple curl handles and add them to a curl_multi handle for unified management.
In order to ensure that all requests have been completed correctly before calling curl_multi_close to release resources, we need to reasonably detect the execution status of each request. This article will explain a standard and reliable way to achieve this requirement.
Usually we follow the following steps to handle multiple requests:
Initialize multiple curl separate handles.
Add these handles to a curl_multi handle.
Continuously execute requests using curl_multi_exec .
Use curl_multi_select to cooperate with curl_multi_exec to detect whether a request has been completed.
Removes completed request handles one by one.
Make sure that all requests are completed, then call curl_multi_close .
Here is a complete example, assuming we need to request multiple URLs (here we take https://gitbox.net/example1 and https://gitbox.net/example2 as examples):
<?php
// initialization cURL multi Handle
$multiHandle = curl_multi_init();
// Store each cURL Handle的数组
$curlHandles = [];
// To request URL List
$urls = [
'https://gitbox.net/example1',
'https://gitbox.net/example2',
];
// Create and add each cURL Handle
foreach ($urls as $i => $url) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_multi_add_handle($multiHandle, $ch);
$curlHandles[$i] = $ch;
}
// implement multi ask
$running = null;
do {
$status = curl_multi_exec($multiHandle, $running);
// prevent CPU Idle
if ($status == CURLM_OK) {
curl_multi_select($multiHandle);
} else {
break;
}
// 检查是否有已完成的ask
while ($info = curl_multi_info_read($multiHandle)) {
if ($info['msg'] == CURLMSG_DONE) {
// 获取完成的Handle
$completedHandle = $info['handle'];
// Get the returned content
$response = curl_multi_getcontent($completedHandle);
// The returned data can be processed here
echo "ask完成,Return data length:" . strlen($response) . PHP_EOL;
// 移除并关闭已完成的Handle
curl_multi_remove_handle($multiHandle, $completedHandle);
curl_close($completedHandle);
}
}
} while ($running > 0);
// Last Close multi Handle
curl_multi_close($multiHandle);
curl_multi_exec : Promote the execution of concurrent requests and return the number of connections that are still running.
curl_multi_select : used to block and wait for active connections to reduce waste of CPU resources.
curl_multi_info_read : Detects whether a request has been completed and can process completed handles at one time.
curl_multi_close is called only when $running == 0 and all the clone handles have been removed and closed.
If there are many requests, it is recommended to add a timeout mechanism to prevent some requests from getting stuck for a long time.
curl_multi_select sometimes returns -1 , in this case, you need to use usleep() for small waits to prevent a dead loop.
if (curl_multi_select($multiHandle) == -1) {
usleep(100);
}
This ensures that the script is more robust.
Before using curl_multi_close , the key is to confirm that all subrequests have been completed and cleaned correctly. The above pattern is a common and recommended standard practice.
Understanding the behavior of the curl_multi_* series will help write more efficient and stable concurrent network request code!