0
0

More than 3 years have passed since last update.

Windows版PHPでのusleepは引数の値がどの辺りから結果が横這いになるのか

Last updated at Posted at 2020-05-08

前回 “PHP usleepより高い精度でスリープしたい” にて

Windowsではusleepに指定する値がある程度小さくなると結果が変わらなくなってくるので

と書きましたが、かなり以前に軽く試した程度でしたので、再度確認してみました。

スクリプト

確認に使ったスクリプトは以下になります。

test.php
<?php
for($l = 1000000; $l >= 1; $l /= 10) {
    for($sleep_mt = $l; $sleep_mt >= 1; $sleep_mt -= $l / 10) {
        sleep(1);
        $sleep_res[$sleep_mt] = sleep_loop($sleep_mt);
    }
}

print "|argument |      actual |       ideal | accuracy|\n";
foreach($sleep_res as $key => $val) {
    printf("|%8d | %.9f | %.9f | %7.3f%%|\n", $key, $val, $key / 1e6, ($key / 1e4) / $val);
}

function sleep_loop($sleep) {
    $loopCount = ($n = ceil(1e6 / $sleep)) > 1000 ? 1000 : $n;
    printf("usleep(%d) loopcount:%d\n", $sleep, $loopCount);
    $buffArray = [];
    for($i = 0; $i < $loopCount; $i++) {
        $start = gettimeofday();
        usleep($sleep);
        $end = gettimeofday();
        $t = $buffArray[] = $end['sec'] - $start['sec'] + ($end['usec'] - $start['usec']) / 1e6;
        printf("%d: %.9f\r", $i, $t);
    }
    $av = array_sum($buffArray) / $loopCount;
    print "actual(average) ideal        accuracy\n";
    printf("%.9f     %.9f  %7.3f%%\n\n", $av, $sleep / 1e6, ($sleep / 1e4) / $av);
    return array_sum($buffArray) / $loopCount;
}

結果

Windows

こちら、Windows版PHPで実行した結果です。
usleepに渡した引数、実測値(数回の平均値)、誤差やオーバーヘッドを皆無とした場合の理想値、理想値に対しての精度になります。

argument actual ideal accuracy
1000000 1.004598000 1.000000000 99.542%
900000 0.906128000 0.900000000 99.324%
800000 0.813190000 0.800000000 98.378%
700000 0.704844500 0.700000000 99.313%
600000 0.609229000 0.600000000 98.485%
500000 0.514986000 0.500000000 97.090%
400000 0.407253667 0.400000000 98.219%
300000 0.311733250 0.300000000 96.236%
200000 0.203052400 0.200000000 98.497%
100000 0.108707000 0.100000000 91.990%
90000 0.093679750 0.090000000 96.072%
80000 0.093660769 0.080000000 85.415%
70000 0.078502733 0.070000000 89.169%
60000 0.062928118 0.060000000 95.347%
50000 0.062421800 0.050000000 80.100%
40000 0.046800040 0.040000000 85.470%
30000 0.031325118 0.030000000 95.770%
20000 0.031181740 0.020000000 64.140%
10000 0.015550560 0.010000000 64.306%
9000 0.015549714 0.009000000 57.879%
8000 0.015597080 0.008000000 51.292%
7000 0.015513476 0.007000000 45.122%
6000 0.015546527 0.006000000 38.594%
5000 0.015548400 0.005000000 32.158%
4000 0.015557052 0.004000000 25.712%
3000 0.015410862 0.003000000 19.467%
2000 0.015555192 0.002000000 12.857%
1000 0.015269904 0.001000000 6.549%
900 0.015374730 0.000900000 5.854%
800 0.014939869 0.000800000 5.355%
700 0.015532448 0.000700000 4.507%
600 0.015449516 0.000600000 3.884%
500 0.015041016 0.000500000 3.324%
400 0.015201374 0.000400000 2.631%
300 0.015268615 0.000300000 1.965%
200 0.015033270 0.000200000 1.330%
100 0.015506672 0.000100000 0.645%
90 0.014988844 0.000090000 0.600%
80 0.015085743 0.000080000 0.530%
70 0.014983447 0.000070000 0.467%
60 0.014896100 0.000060000 0.403%
50 0.015412744 0.000050000 0.324%
40 0.015404253 0.000040000 0.260%
30 0.014793728 0.000030000 0.203%
20 0.015019174 0.000020000 0.133%
10 0.015289082 0.000010000 0.065%
9 0.015506825 0.000009000 0.058%
8 0.015441582 0.000008000 0.052%
7 0.015303005 0.000007000 0.046%
6 0.014883630 0.000006000 0.040%
5 0.015491012 0.000005000 0.032%
4 0.015521473 0.000004000 0.026%
3 0.015272744 0.000003000 0.020%
2 0.015507319 0.000002000 0.013%
1 0.015304317 0.000001000 0.007%

引数に10000(1/100秒)以下を指定した場合、結果はほとんど同じになりました。
異なるスペックの複数のPCでもだいたい同様の結果でした。

Linux

Linuxで実行した場合の結果はこんな感じでした。

argument actual ideal accuracy
1000000 1.000119613 1.000000000 99.988%
900000 0.900116641 0.900000000 99.987%
800000 0.800115063 0.800000000 99.986%
700000 0.700112048 0.700000000 99.984%
600000 0.600115420 0.600000000 99.981%
500000 0.500117902 0.500000000 99.976%
400000 0.400114053 0.400000000 99.971%
300000 0.300107420 0.300000000 99.964%
200000 0.200117489 0.200000000 99.941%
100000 0.100117310 0.100000000 99.883%
90000 0.090117912 0.090000000 99.869%
80000 0.080117342 0.080000000 99.854%
70000 0.070116776 0.070000000 99.833%
60000 0.060117303 0.060000000 99.805%
50000 0.050117134 0.050000000 99.766%
40000 0.040117620 0.040000000 99.707%
30000 0.030117647 0.030000000 99.609%
20000 0.020118150 0.020000000 99.413%
10000 0.010116925 0.010000000 98.844%
9000 0.009117167 0.009000000 98.715%
8000 0.008116660 0.008000000 98.563%
7000 0.007117286 0.007000000 98.352%
6000 0.006117258 0.006000000 98.083%
5000 0.005117448 0.005000000 97.705%
4000 0.004108513 0.004000000 97.359%
3000 0.003106908 0.003000000 96.559%
2000 0.002108241 0.002000000 94.866%
1000 0.001107048 0.001000000 90.330%
900 0.001007407 0.000900000 89.338%
800 0.000906241 0.000800000 88.277%
700 0.000807078 0.000700000 86.733%
600 0.000706321 0.000600000 84.947%
500 0.000605894 0.000500000 82.523%
400 0.000484747 0.000400000 82.517%
300 0.000380773 0.000300000 78.787%
200 0.000281204 0.000200000 71.123%
100 0.000161443 0.000100000 61.941%
90 0.000151159 0.000090000 59.540%
80 0.000141270 0.000080000 56.629%
70 0.000142765 0.000070000 49.032%
60 0.000119653 0.000060000 50.145%
50 0.000109219 0.000050000 45.779%
40 0.000099035 0.000040000 40.390%
30 0.000088091 0.000030000 34.056%
20 0.000078189 0.000020000 25.579%
10 0.000067107 0.000010000 14.902%
9 0.000066188 0.000009000 13.598%
8 0.000065196 0.000008000 12.271%
7 0.000064239 0.000007000 10.897%
6 0.000063161 0.000006000 9.500%
5 0.000061892 0.000005000 8.079%
4 0.000060883 0.000004000 6.570%
3 0.000059732 0.000003000 5.022%
2 0.000058932 0.000002000 3.394%
1 0.000057835 0.000001000 1.729%

値が小さくなるに従ってオーバーヘッドの影響も無視できなくなってくるので精度が落ちるのは仕方ありませんが、Windows版と比べたらかなり低い値まで信用できるかな、と思います。

追記

Windows版PHPでも、同時に動いているソフトウエア次第でusleepの値が横這いになり始める閾値が変わるようでした。

argument actual ideal accuracy
100000 0.100642500 0.100000000 99.362%
90000 0.090570583 0.090000000 99.370%
80000 0.080499308 0.080000000 99.380%
70000 0.070486467 0.070000000 99.310%
60000 0.060393294 0.060000000 99.349%
50000 0.050311800 0.050000000 99.380%
40000 0.040265600 0.040000000 99.340%
30000 0.030161941 0.030000000 99.463%
20000 0.020167180 0.020000000 99.171%
10000 0.010274510 0.010000000 97.328%
9000 0.009216366 0.009000000 97.652%
8000 0.008228112 0.008000000 97.228%
7000 0.007263986 0.007000000 96.366%
6000 0.006263365 0.006000000 95.795%
5000 0.005298985 0.005000000 94.358%
4000 0.004333180 0.004000000 92.311%
3000 0.003362692 0.003000000 89.214%
2000 0.002429720 0.002000000 82.314%
1000 0.001439262 0.001000000 69.480%
900 0.000987596 0.000900000 91.130%
800 0.000992589 0.000800000 80.597%
700 0.000992307 0.000700000 70.543%
600 0.000988720 0.000600000 60.685%
500 0.000987593 0.000500000 50.628%
400 0.000987899 0.000400000 40.490%
300 0.000988207 0.000300000 30.358%
200 0.000988125 0.000200000 20.240%
100 0.000988660 0.000100000 10.115%
90 0.000988996 0.000090000 9.100%
80 0.000988034 0.000080000 8.097%
70 0.000993000 0.000070000 7.049%
60 0.000988955 0.000060000 6.067%
50 0.000988196 0.000050000 5.060%
40 0.000988778 0.000040000 4.045%
30 0.000988507 0.000030000 3.035%
20 0.000988754 0.000020000 2.023%
10 0.000988374 0.000010000 1.012%
9 0.000988151 0.000009000 0.911%
8 0.000988197 0.000008000 0.810%
7 0.001001757 0.000007000 0.699%
6 0.000987563 0.000006000 0.608%
5 0.000987617 0.000005000 0.506%
4 0.000988710 0.000004000 0.405%
3 0.000988145 0.000003000 0.304%
2 0.000988444 0.000002000 0.202%
1 0.000988313 0.000001000 0.101%

100000より上は記載を省略していますが、Windowsでも10000を下回っても結果が下がり続け、1000未満で横這いになり始めるといったケースがありました。

何が影響するのか確認

test.php
<?php
while(true) {
    $r = [];
    $t = time();
    while($t === time()) {
        $start = gettimeofday();
        usleep(1000);
        $end = gettimeofday();
        $r[] = $end['sec'] - $start['sec'] + ($end['usec'] - $start['usec']) / 1e6;
    }
    printf("%.9f\n", array_sum($r) / count($r));
}

上記のスクリプトを実行させながらいくつかの別のソフトウェアを立ち上げたり終了させたりしてみたところ、Google Chrome(確認したバージョンは81.0.4044.138)を実行した時に大きく変動するようでした。
とくに、タイマー系のjavascriptの処理の影響が大きいようで、Chromeで例えば

setInterval(1000, function(){});

を走らせているだけでもusleepの精度が上がり、Chromeを閉じると元に戻りました。
他のブラウザだと、firefoxは影響なし、EdgeやIEはChromeの半分くらい影響、といった感じでした。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0