要約: (この投稿は、さまざまな手段をテストした結果、壮大なものになりました)
PHP は、切断を検出するか、出力を配信するために、通常 2 回の while ループの反復を行います。この遅延は、Web サーバー ソフトウェア、ホスト コンピューター、クライアント コンピューター、およびクライアント ブラウザーに起因する可能性がありますが、反復ごとのスリープによって異なるはずです。遅延は、PHP の内部実行または出力プロセス (おそらく小さな内部バッファーまたは割り込み処理プロセス) から発生している可能性があります。
エピック投稿:
[Refresh] またはURL 送信からの実行時間をカウントすることは、正確な開始点ではありません。最初に必要な手順がいくつでもあり、遅延が増える可能性があります。
- DNS ルックアップが必要 (TCP オーバーヘッドあり)
- サーバーとの TCP 接続が確立されました
- Web サーバーがスレッドまたは子を作成する
- Web サーバーがリクエストの処理方法を決定する
- PHP の起動が必要な場合があります
- PHP でソースをオペコードに変換する必要がある場合があります
そこで、[Refresh] -> [Stop] 時間を測定して PHP によって記録された数値と比較するのではなく、表示された出力と記録された出力を測定しました。変更されたスクリプトは実行できず (一定回数の反復後に終了します)、既定のphp.ini
バッファリングをクリアし、反復回数を画面とタイミング ファイルに報告します。$sleep
効果を確認するために、さまざまな期間でスクリプトを実行しました。最終的なスクリプト:
<?php
date_default_timezone_set('America/Los_Angeles'); //Used by ob apparently
ignore_user_abort(true); //Don't terminate script because user leaves
set_time_limit(0); //Allow runaway script !danger !danger
while (@ob_end_flush()) {}; //By default set on/4K in php.ini
$start=microtime(true);
$n=1000;
$i=0;
$sleep=100000;// 0.1s
while(!connection_aborted() && $i<$n) {
echo "\n[".++$i."]";flush();
usleep($sleep);
}
$end=microtime(true);
file_put_contents("timing.txt",
"#\$sleep=".($sleep/1000000).
"s\n/ s=$start / e=$end ($i) / d=".($end-$start)."\n",
FILE_APPEND);
?>
結果: (複数の実行を連結し、Firefox で実行)
# On-screen $i / start utime / end utime (current $i) / delta utime
#$sleep=1s
2 / s=1296251342.5729 / e=1296251346.5721 (4) / d=3.999242067337
3 / s=1296251352.9094 / e=1296251357.91 (5) / d=5.000559091568
#$sleep=0.1s
11 / s=1296251157.982 / e=1296251159.2896 (13) / d=1.3075668811798
8 / s=1296251167.5659 / e=1296251168.5709 (10) / d=1.0050280094147
16 / s=1296251190.0493 / e=1296251191.8599 (18) / d=1.810576915741
4 / s=1296251202.7471 / e=1296251203.3505 (6) / d=0.60339689254761
16 / s=1296251724.5782 / e=1296251726.3882 (18) / d=1.8099851608276
#$sleep=0.01s
42 / s=1296251233.0498 / e=1296251233.5217 (44) / d=0.47195816040039
62 / s=1296251260.4463 / e=1296251261.1336 (64) / d=0.68735003471375
150 / s=1296251279.2656 / e=1296251280.901 (152) / d=1.6353850364685
379 / s=1296252444.7587 / e=1296252449.0108 (394) / d=4.2521529197693
#$sleep=0.001s
337 / s=1296251293.4823 / e=1296251294.1515 (341) / d=0.66925406455994
207 / s=1296251313.7312 / e=1296251314.1445 (211) / d=0.41328597068787
792 / s=1296251324.5233 / e=1296251326.0915 (795) / d=1.5682451725006
(Opera は数値を表示しませんが、最終的にはほぼ一致する数値を表示します)
(Chrome はテスト中/テスト後に
何も表示しません) (Safari はテスト中/テスト後に何も
表示しません) (IE は何も表示しません)試験中/試験後)
各行の最初の数字は、[停止] が押されたときに画面に表示される数字を示します (手動で記録)。
いくつかのポイント:
- スクリプトは各 while 反復の開始時にのみチェックするため、終了点は最も近い
$sleep
周期 (上記のスクリプトでは 1/10 秒) に量子化されusleep
ます。メソッドは完全な遅延ではないため、多少の変動があります。
- 使用しているブラウザとサーバーによって違いが生じます。フラッシュのマニュアル ページには、「Web サーバーのバッファリング スキームをオーバーライドできない可能性があり、ブラウザのクライアント側のバッファリングには影響しない」と記載されています。次に、サーバーとクライアントの両方の問題について詳しく説明します。[サーバー: WinXPsp3 / Apache 2.2.17 / PHP 5.3.3 クライアント: WinXPsp3 / FireFox 3.6.13]
分析:
0.001 秒の遅延を除いて、[停止] と PHP がそれをキャッチする (または Firefox または Apache のレポート) 間に 2 反復の遅延が見られます。遅延が 0.001 秒の場合、少し異なります。平均は 4 回の反復または 0.004 秒です。これはおそらく、検出速度のしきい値に近づいています。
遅延時間が 0.1 秒以上の場合、実行時間は$sleep
* {recorded iterations} とほぼ一致しています。
遅延時間が 0.1 秒未満の場合、スリープ時間よりも大きな実行遅延が見られます。これは、クライアント接続のチェック、インクリメント$i
、テキストの出力、および反復ごとのバッファーのフラッシュのコストによるものと思われます。実行時間との不一致$i*$sleep
はかなり線形であり、これらのタスクを完了するのに約 0.001 秒/反復かかることを示唆しています (0.01 秒のスリープでは 0.0008 ですが、0.001 秒のスリープでは 0.0010 になります。おそらくMALLOC
/output の増加の結果です)。