前回 “PHP usleepより高い精度でスリープしたい” にて
Windowsではusleepに指定する値がある程度小さくなると結果が変わらなくなってくるので
と書きましたが、かなり以前に軽く試した程度でしたので、再度確認してみました。
スクリプト
確認に使ったスクリプトは以下になります。
<?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未満で横這いになり始めるといったケースがありました。
何が影響するのか確認
<?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の半分くらい影響、といった感じでした。