- Notifications
You must be signed in to change notification settings - Fork821
Description
When starting a MultiCurl batch with >1 parallel connections, in the default case no handling actions are taken (executing callbacks or starting new connections) until a whole parallel batch is concluded
This is because of the loop at
php-curl-class/src/Curl/MultiCurl.php
Lines 691 to 693 inb9e9259
do { | |
$status =curl_multi_exec($this->multiCurl,$active); | |
}while ($status ===CURLM_CALL_MULTI_PERFORM); |
This doesn't happen when calling setRequestTimeAccuracy() before starting the MultiCurl, since the other branch is executed.
Since i couldn't trigger the curl_multi_exec error described in the previous lines, I don't know what can be changed and what cannot, so I'm writing this issue instead.
Here is a simple test to replicate the issue:
useCurl\MultiCurl;constTEST_URL="https://ash-speed.hetzner.com/100MB.bin";$multi_curl =newMultiCurl();//$multi_curl->setRequestTimeAccuracy(); //Uncomment for expected output$start_time=microtime(true);foreach(range(1,12)as$i){$ch=$multi_curl->addGet(TEST_URL);$ch->setOpt(CURLOPT_MAX_RECV_SPEED_LARGE,100*$i*1024);$ch->setRange("0-".(500*1024));$ch->beforeSend(function()use ($i,$start_time){echo"Start$i at".round(microtime(true)-$start_time,2)."\n";});$ch->complete(function()use ($i,$start_time){echo"End$i at".round(microtime(true)-$start_time,2)."\n";});}$multi_curl->setConcurrency(3);$multi_curl->start();
This downloads the first 500KB of a test file multiple times, at speeds increasing by 100KB/s for every connection, and with 3 parallel connections
This means that connection 1 should take 500/100 = 5 seconds, connection 2 should take 500/200 = 2.5 seconds, and so on
Without calling setRequestTimeAccuracy, this is the output I get
Start 1 at 0Start 2 at 0Start 3 at 0End 3 at 4.96End 2 at 4.96End 1 at 4.97Start 4 at 4.97Start 5 at 4.97Start 6 at 4.97End 6 at 6.21End 5 at 6.21End 4 at 6.22Start 7 at 6.22Start 8 at 6.22Start 9 at 6.22End 9 at 6.93End 8 at 6.93End 7 at 6.93Start 10 at 6.93Start 11 at 6.93Start 12 at 6.93End 12 at 7.43End 11 at 7.44End 10 at 7.44
As you can see, while connection 3 is supposed to be 3 times faster, it will wait until connection 1 and 2 are finished, and then connections 4, 5 and 6 will be started
When calling setRequestTimeAccuracy, the output becomes
Start 1 at 0Start 2 at 0Start 3 at 0End 3 at 1.66Start 4 at 1.66End 2 at 2.48Start 5 at 2.48End 4 at 2.9Start 6 at 2.9End 5 at 3.48Start 7 at 3.48End 6 at 3.73Start 8 at 3.73End 7 at 4.19Start 9 at 4.19End 8 at 4.35Start 10 at 4.35End 9 at 4.74Start 11 at 4.74End 10 at 4.85Start 12 at 4.85End 1 at 4.96End 11 at 5.19End 12 at 5.26
Now, the callback for connection 3 is called as expected, and connection 4 is started right after
The total runtime is also lower, since new connections are started as soon as possible