mirror of
https://github.com/php-curl-class/php-curl-class.git
synced 2026-09-15 21:06:33 +00:00
Improve MultiCurl::waitUntilRequestQuotaAvailable (#1016)
* Include keyword * Use numeric literal separators * Improve waitUntilRequestQuotaAvailable using new TimeUtil
This commit is contained in:
@@ -38,7 +38,7 @@ Installation instructions to use the `composer` command can be found on https://
|
||||
|
||||
### 📋 Requirements
|
||||
|
||||
PHP Curl Class works with PHP 8.4, 8.3, 8.2, 8.1, and 8.0.
|
||||
PHP Curl Class works with PHP versions 8.4, 8.3, 8.2, 8.1, and 8.0.
|
||||
|
||||
### 🚀 Quick Start and Examples
|
||||
|
||||
|
||||
+19
-18
@@ -687,7 +687,7 @@ class MultiCurl extends BaseCurl
|
||||
// pending requests to have more accurate start times. Without a shorter timeout, it can be nearly a
|
||||
// full second before available request quota is rechecked and pending requests can be initialized.
|
||||
if (curl_multi_select($this->multiCurl, 0.2) === -1) {
|
||||
usleep(100000);
|
||||
usleep(100_000);
|
||||
}
|
||||
|
||||
curl_multi_exec($this->multiCurl, $active);
|
||||
@@ -944,27 +944,28 @@ class MultiCurl extends BaseCurl
|
||||
*/
|
||||
private function waitUntilRequestQuotaAvailable()
|
||||
{
|
||||
$sleep_until = (float)($this->currentStartTime + $this->intervalSeconds);
|
||||
$sleep_seconds = $sleep_until - microtime(true);
|
||||
$sleep_until = TimeUtil::getSleepUntilMicrotime(
|
||||
$this->currentStartTime,
|
||||
$this->intervalSeconds,
|
||||
);
|
||||
|
||||
// Avoid using time_sleep_until() as it appears to be less precise and not sleep long enough.
|
||||
// Avoid using usleep(): "Values larger than 1000000 (i.e. sleeping for
|
||||
// more than a second) may not be supported by the operating system.
|
||||
// Use sleep() instead."
|
||||
$sleep_seconds_int = (int)$sleep_seconds;
|
||||
if ($sleep_seconds_int >= 1) {
|
||||
sleep($sleep_seconds_int);
|
||||
$current_microtime = microtime(true);
|
||||
$sleep_seconds = TimeUtil::getSleepSecondsUntilMicrotime(
|
||||
$sleep_until,
|
||||
$current_microtime,
|
||||
);
|
||||
|
||||
list($whole_seconds, $microseconds_remainder) = TimeUtil::getWholeAndRemainderSeconds($sleep_seconds);
|
||||
|
||||
if ($whole_seconds >= 1) {
|
||||
sleep($whole_seconds);
|
||||
}
|
||||
|
||||
if ($microseconds_remainder > 0) {
|
||||
usleep($microseconds_remainder);
|
||||
}
|
||||
|
||||
// Ensure that enough time has passed as usleep() may not have waited long enough.
|
||||
$this->currentStartTime = microtime(true);
|
||||
if ($this->currentStartTime < $sleep_until) {
|
||||
do {
|
||||
usleep(1000000 / 4);
|
||||
$this->currentStartTime = microtime(true);
|
||||
} while ($this->currentStartTime < $sleep_until);
|
||||
}
|
||||
|
||||
$this->currentRequestCount = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Curl;
|
||||
|
||||
class TimeUtil
|
||||
{
|
||||
/**
|
||||
* Get the microtime (in microseconds) at which to sleep until.
|
||||
*
|
||||
* @param float $start_time The start time in seconds with microsecond precision.
|
||||
* @param int $interval_seconds The interval in seconds.
|
||||
* @return float The microtime (in microseconds) at which to sleep until.
|
||||
*/
|
||||
public static function getSleepUntilMicrotime(
|
||||
float $start_time,
|
||||
int $interval_seconds,
|
||||
): float {
|
||||
$result = $start_time + (float)$interval_seconds;
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of seconds to sleep until the specified microtime.
|
||||
*
|
||||
* @param float $sleep_until_microtime The microtime (in microseconds) at which to sleep until.
|
||||
* @param float $current_microtime The current microtime (in microseconds).
|
||||
* @return float The number of seconds to sleep.
|
||||
*/
|
||||
public static function getSleepSecondsUntilMicrotime(
|
||||
float $sleep_until_microtime,
|
||||
float $current_microtime,
|
||||
): float {
|
||||
$result = $sleep_until_microtime - $current_microtime;
|
||||
|
||||
// Always round up with microsecond precision to avoid sleeping less
|
||||
// than required.
|
||||
$rounded_up_result = ceil($result * (float)1_000_000) / (float)1_000_000;
|
||||
return $rounded_up_result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the whole seconds and microseconds remainder from the given sleep
|
||||
* seconds.
|
||||
*
|
||||
* @param float $sleep_seconds The number of seconds to sleep.
|
||||
* @return array An array containing the whole seconds and microseconds remainder.
|
||||
*/
|
||||
public static function getWholeAndRemainderSeconds(
|
||||
float $sleep_seconds,
|
||||
): array {
|
||||
$micros = (int) ceil($sleep_seconds * (float)1_000_000);
|
||||
$whole_seconds = intdiv($micros, 1_000_000);
|
||||
$microseconds_remainder = $micros % 1_000_000;
|
||||
return [
|
||||
$whole_seconds,
|
||||
$microseconds_remainder,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CurlTest;
|
||||
|
||||
use Curl\TimeUtil;
|
||||
|
||||
class TimeUtilTest extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
public function testGetSleepUntilMicrotime()
|
||||
{
|
||||
// Use a fixed start time.
|
||||
// [...]ime = microtime(true);
|
||||
$start_time = (float)1_750_000_000.123456;
|
||||
|
||||
// Use a fixed current time that occurs after the start time.
|
||||
// [...]_microtime = (float)1_750_000_045.000001;
|
||||
$current_microtime = (float)1_750_000_044.999999;
|
||||
|
||||
$interval_seconds = 60;
|
||||
$sleep_until_microtime = TimeUtil::getSleepUntilMicrotime(
|
||||
$start_time,
|
||||
$interval_seconds,
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
(float)1_750_000_060.123456,
|
||||
$sleep_until_microtime,
|
||||
);
|
||||
}
|
||||
|
||||
public function testGetSleepSecondsUntilMicrotime()
|
||||
{
|
||||
$sleep_until_microtime = (float)1_750_000_060.123456;
|
||||
$current_microtime = (float)1_750_000_044.999999;
|
||||
|
||||
$sleep_seconds = TimeUtil::getSleepSecondsUntilMicrotime(
|
||||
$sleep_until_microtime,
|
||||
$current_microtime,
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
(float)15.123457,
|
||||
$sleep_seconds,
|
||||
);
|
||||
}
|
||||
|
||||
public function testGetWholeAndRemainderSeconds()
|
||||
{
|
||||
$sleep_seconds = (float)15.123457;
|
||||
|
||||
list($whole_seconds, $microseconds_remainder) = TimeUtil::getWholeAndRemainderSeconds(
|
||||
$sleep_seconds,
|
||||
);
|
||||
|
||||
$this->assertEquals(15, $whole_seconds);
|
||||
$this->assertEquals(123457, $microseconds_remainder);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -323,7 +323,7 @@ if ($test === 'http_basic_auth') {
|
||||
|
||||
$dots_printed = 0;
|
||||
while (true) {
|
||||
usleep(1000000 / 100);
|
||||
usleep(1_000_000 / 100);
|
||||
|
||||
$elapsed = microtime(true) - $start;
|
||||
$dots_to_print = floor($elapsed) - $dots_printed;
|
||||
|
||||
Reference in New Issue
Block a user