When using the curl_multi function in PHP, you may encounter a common situation: during the process of multi-request parallel processing, curl_multi_close() may interrupt the currently ongoing request. This problem sometimes causes the program to fail to complete all concurrent requests smoothly, so appropriate measures are required to avoid this problem. This article will introduce how to effectively deal with the problem of curl_multi_close interruption during the request process.
curl_multi_close() is a function provided by PHP's cURL extension to close cURL multiple handles created by curl_multi_init() . Its function is to release the resource, but if the function is called in advance during the request process, it is possible to interrupt the unfinished request. This may lead to data loss or incomplete requests, which will affect the stability and performance of the system.
Here is a simple curl_multi request example:
<?php
// initialization curl_multi Handle
$mh = curl_multi_init();
// Create multiple cURL Handle
$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);
// Put each cURL Handle添加到 multi Handle中
curl_multi_add_handle($mh, $ch1);
curl_multi_add_handle($mh, $ch2);
// Perform all requests
$running = null;
do {
$mrc = curl_multi_exec($mh, $running);
} while ($running > 0);
// Get the returned data
$response1 = curl_multi_getcontent($ch1);
$response2 = curl_multi_getcontent($ch2);
// closure cURL Handle
curl_multi_remove_handle($mh, $ch1);
curl_multi_remove_handle($mh, $ch2);
// closure multi Handle
curl_multi_close($mh);
?>
In this example, we add multiple cURL handles to the multiple handle $mh through curl_multi_add_handle() and execute all requests in parallel via curl_multi_exec() . Finally, we close the multi-handle via curl_multi_remove_handle() and curl_multi_close() .
The problem occurs when curl_multi_close() is called, which may close multiple handles in advance, resulting in the request being interrupted midway. If an interrupt occurs when all requests have not been completed, the unfinished request will not be able to obtain response data or return results.
To ensure that curl_multi_close() does not interrupt the request, the following methods can be used:
The most common solution is to make sure that all requests have been completed and then call curl_multi_close() . You can use the return value of curl_multi_exec() to determine whether all requests have been completed. When the value of the running variable is 0, it means that all requests have been completed. Only then is curl_multi_close() called.
The modified code is as follows:
<?php
// initialization curl_multi Handle
$mh = curl_multi_init();
// Create multiple cURL Handle
$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);
// Put each cURL Handle添加到 multi Handle中
curl_multi_add_handle($mh, $ch1);
curl_multi_add_handle($mh, $ch2);
// Perform all requests
$running = null;
do {
$mrc = curl_multi_exec($mh, $running);
// A small delay can be added here to slow down CPU Usage rate
usleep(100);
} while ($running > 0);
// Get the returned data
$response1 = curl_multi_getcontent($ch1);
$response2 = curl_multi_getcontent($ch2);
// closure cURL Handle
curl_multi_remove_handle($mh, $ch1);
curl_multi_remove_handle($mh, $ch2);
// closure multi Handle
curl_multi_close($mh);
?>
The request is continuously executed through a do-while loop until running is 0, at which time all requests have been completed, and curl_multi_close() can be safely called.
Sometimes, even if all requests seem to have been completed, they may be interrupted due to problems such as network failures. At this time, you can consider retrying when the request fails.
<?php
// Set the maximum number of retry times
$maxRetries = 3;
function performRequest($ch, $maxRetries) {
$retryCount = 0;
$response = null;
while ($retryCount < $maxRetries) {
$response = curl_exec($ch);
if ($response !== false) {
break;
}
$retryCount++;
usleep(500000); // Wait for a while before trying again
}
return $response;
}
// initialization curl_multi Handle
$mh = curl_multi_init();
// Create multiple cURL Handle
$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);
// Put each cURL Handle添加到 multi Handle中
curl_multi_add_handle($mh, $ch1);
curl_multi_add_handle($mh, $ch2);
// Perform all requests
$running = null;
do {
$mrc = curl_multi_exec($mh, $running);
} while ($running > 0);
// Get the returned data,Try again
$response1 = performRequest($ch1, $maxRetries);
$response2 = performRequest($ch2, $maxRetries);
// closure cURL Handle
curl_multi_remove_handle($mh, $ch1);
curl_multi_remove_handle($mh, $ch2);
// closure multi Handle
curl_multi_close($mh);
?>
In the above code, the performRequest() function tries to retry when the request fails until the maximum number of retries is reached. This can effectively avoid request interruptions due to network problems.
curl_multi_select() can help PHP programs handle multiple requests more efficiently, avoiding calling curl_multi_exec() in each loop. It will continue to execute the request when certain conditions are met, which can save system resources.
<?php
// initialization curl_multi Handle
$mh = curl_multi_init();
// Create multiple cURL Handle
$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);
// Put each cURL Handle添加到 multi Handle中
curl_multi_add_handle($mh, $ch1);
curl_multi_add_handle($mh, $ch2);
// Perform all requests
$running = null;
do {
curl_multi_select($mh);
$mrc = curl_multi_exec($mh, $running);
} while ($running > 0);
// Get the returned data
$response1 = curl_multi_getcontent($ch1);
$response2 = curl_multi_getcontent($ch2);
// closure cURL Handle
curl_multi_remove_handle($mh, $ch1);
curl_multi_remove_handle($mh, $ch2);
// closure multi Handle
curl_multi_close($mh);
?>
curl_multi_select() can wait when there is no available data, thus avoiding unnecessary CPU usage. It is a more efficient way, especially when there are a lot of requests.