Abs*_*Abs 14 php time microtime
任何人都可以告诉我为什么当我运行具有以下内容的脚本然后在5秒后停止它,我需要将经过时间除以2以获得正确的脚本执行时间?
ignore_user_abort(true); set_time_limit(0);
$begin_time = microtime(true);
$elapsed_time = 0;
while(!connection_aborted()) {
echo ' ';
flush();
usleep(1000000);
}
$elapsed_time = microtime(true) - $begin_time;
$timer_seconds = $elapsed_time; //10 seconds
$timer_seconds = $elapsed_time / 2; //5 seconds
/*I am writing to a DB - but you can use this to test */
$fp = fopen('times.txt', 'w');
fwrite($fp, 'Time Elapsed: '.$timer_seconds);
fclose($fp);
Run Code Online (Sandbox Code Playgroud)
随意尝试代码,因为它困扰我为什么$elapsed_time需要被两个分开.也许我误会了什么?
谢谢大家的帮助
我已更新代码,以便任何人都可以尝试这个,它将写入文本文件以查看输出.
sha*_*mar 13
原始代码发生重大变化:
1)使用implicit_flush并在执行任何操作之前刷新所有缓冲区.
2)代码不输出空格,而是输出迭代次数和1023字节的其他数据,告诉浏览器我们要显示的输出量很大.一个正常的已知技巧.
3)除了节省输出文本文件中的时间外,它还节省了代码运行的总迭代次数.
使用的代码:
<?php
// Tricks to allow instant output
@ini_set('implicit_flush', 1);
for ($i = 0; $i < ob_get_level(); $i++)
ob_end_flush();
ob_implicit_flush(1);
//Your Code starts here
ignore_user_abort(true);
set_time_limit(0);
$begin_time = microtime(true);
$elapsed_time = 0;
while(!connection_aborted())
{
//this I changed, so that a looooong string is outputted
echo $i++.str_repeat(' ',1020).'<br/>';
flush();
usleep(1000000);
}
$elapsed_time = microtime(true) - $begin_time;
$timer_seconds = $elapsed_time; //10 seconds
//Writes to file the number of ITERATIONS too along with time
$fp = fopen('4765107.txt', 'w');
fwrite($fp, 'Time Elapsed: '.$timer_seconds);
fwrite($fp, "\nIterations: ".$i);
fclose($fp);
?>
Run Code Online (Sandbox Code Playgroud)
现场演示:
现在,这是运行的代码:http: //work.sktnetwork.com/so/4765107.php
这是它生成的.TXT文件:http: //work.sktnetwork.com/so/4765107.txt
1)当代码运行10次迭代并且单击浏览器上的STOP按钮时,输出文件显示13次迭代,采用~13.01秒.
2)当代码运行20次迭代并且单击浏览器上的STOP按钮时,输出文件显示23次迭代,采用~23.01秒.
1)当单击STOP按钮但单击2-4秒后,脚本实际上不会停止.因此,浏览器中会出现更多迭代.
2)迭代次数是SAME,即执行所需的秒数,如输出文件所示.
因此,没有错误,显然没有错误,只是单击STOP按钮和实际停止的脚本之间的延迟时间.
笔记:
1)服务器:Linux VPS.
2)测试的客户端:Firefox和Chrome.
3)当脚本在单击STOP后2-4秒结束时,输出文件需要大约3-4秒才能更新当前测试.
摘要:(这篇文章在我测试各种途径时变成了史诗)
PHP通常需要两次循环迭代来检测断开连接或提供输出.此延迟可能来自Web服务器软件,主机,客户端计算机和客户端浏览器,但它应根据每次迭代的睡眠而变化.更有可能的是,延迟来自PHP的内部执行或输出过程(可能来自一个小的内部缓冲区或中断处理过程).
史诗贴:
从[Refresh]或URL-submit计算执行时间并不是一个准确的起点 - 可能需要先执行任意数量的步骤,这可能会增加延迟:
因此,不是测量[刷新] - > [停止]时间并将其与PHP记录的数字进行比较,而是测量显示输出到记录输出 - 这将延迟测量减少到大部分只在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);
?>
Run Code Online (Sandbox Code Playgroud)
结果:(连续多次运行,在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
Run Code Online (Sandbox Code Playgroud)
(Opera不显示数字,但显示大致匹配的最终数字)
(Chrome在测试期间/之后不显示任何内容)
(Safari 在测试期间/之后不显示任何内容)
(IE不显示任何内容)在测试期间/之后)
每行上的第一个数字表示按下[停止]后手动记录的屏幕上显示的数字.
几点:
$sleep周期(上述脚本中的1/10s),因为脚本仅在每次迭代开始时检查,因为该usleep方法不是完美的延迟,所以存在一些变化.分析:
除了0.001秒延迟之外,我们在[stop]和PHP捕获它(或Firefox或Apache报告)之间看到了2次迭代延迟.延迟为0.001秒时,它会变化一点,平均值为~4次迭代或0.004秒 - 这可能接近检测速度阈值.
当延迟时间为0.1秒或更长时,我们看到执行时间紧密匹配$sleep*{记录的迭代}.
当延迟时间低于0.1秒时,我们发现执行延迟大于休眠时间.这可能来自检查客户端连接,递增$i,输出文本以及每次迭代刷新缓冲区的成本.执行时间之间的差异$i*$sleep非常线性,表明完成这些任务需要约0.001秒/迭代(0.01s睡眠时为0.0008,而0.001s睡眠时间为0.0010 - 可能是增加MALLOC/输出的结果).
您依赖的connection_aborted()是true当您点击浏览器中的"停止"按钮时,但没有证据表明您已经确认是这种情况.事实上,事实并非如此.
您忘记了网络中"连接中止"检查的方式.应用程序(在这种情况下为php)在尝试写入管道之前不知道发生了什么.
关于文档connection_abort()的第一条评论说:"为了检测脚本内部的断开连接,我们需要刷新缓冲区(只有当服务器尝试发送缓冲区内容时才会看到连接断开). "
所以我不相信你能connection_abort()以这种方式可靠地使用.
放心,microtime()工作正常.