3

我为我担心无法正常工作的部分代码创建了简单的基准。我想出了非常奇怪的结果。看看这个基准:
基准
测试文件

基准代码是:

$start = microtime(true)*1000;

//code
$log=file_get_contents('test.txt').'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'."\n";
file_put_contents('test.txt', $log, LOCK_EX);

$end=microtime(true)*1000;
$time = $end-$start;
echo 'Time : '.(int)$time.'ms<br />';


$start = microtime(true)*1000;

//code
$log='aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'."\n";
file_put_contents('test.txt', $log, LOCK_EX|FILE_APPEND);

$end=microtime(true)*1000;
$time = $end-$start;
echo 'Time : '.(int)$time.'ms<br />';

我注意到的是,我认为应该更快的附加选项实际上更慢。如果问题出在我的基准测试上,请告诉我。
谁能解释一下为什么它可能会变慢?

此外,我发现当您按住 F5(不断刷新)时,文本文件会被清除(:O)为什么?

编辑 正如 Ilya Bursov 所说,我现在已经将基准更改为 100 次迭代。追加操作现在似乎花费了可以忽略不计的时间来完成,而读取和写入则需要永远。然而,即使在清除缓存时,单次迭代仍然会产生奇怪的结果。我知道这可能会受到许多事情的影响,甚至是误差范围,但我们将不胜感激。

4

2 回答 2

4

实际上,您是在错误的环境中用错误的方法测量错误的项目

  1. 对于第一个结果,您正在测量大数据的读取 + 写入
  2. 对于第二个结果,您正在测量变量初始化 + 附加小数据
  3. 您只进行了 1 次迭代,这在多线程环境中会产生非常不稳定的结果
  4. 你通过apache调用脚本,做基准测试最好从命令行调用它
  5. 磁盘/系统缓存缓冲区的不同设置可以真正改变结果

以下是我的猜测,为什么时间如此不同:

由于您只有 1 次流程迭代,因此您可能会遇到以下情况:

  1. 读取文件(它在缓存中) - 我们可以在这里考虑 0 次
  2. 使用 const 连接文件 - 几乎 0 次
  3. 将数据写入输出缓冲区 - 不是写入磁盘,而是写入内存缓冲区,稍后将刷新 - 几乎为 0 次
  4. 现在你正在重新初始化变量 - 我希望 0 次,或者它可以更大,因为你正在重用变量它可能 php 在内存中重新排列一些东西
  5. 您正在写入文件,但是您必须等到 p3 的缓冲区实际被刷新

您可以尝试稍微更改一下代码:

$start = microtime(true)*1000;
$log=file_get_contents('test.txt').'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'."\n";
file_put_contents('test.txt', $log, LOCK_EX);
clearstatcache(); // NOTE call here
$end=microtime(true)*1000;
$time = $end-$start;
echo 'Time : '.(int)$time.'ms<br />';
$start = microtime(true)*1000;
$log='aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'."\n";
file_put_contents('test.txt', $log, LOCK_EX|FILE_APPEND);
clearstatcache(); // NOTE another call here
$end=microtime(true)*1000;
$time = $end-$start;
echo 'Time : '.(int)$time.'ms<br />';

现在你得到了不同的结果

所以

测试中的时间 1:从缓存中读取和写入

时间 2 是实际写入磁盘,可能是内存操作的一些开销

考虑以下代码:

$appendString = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
$log=file_get_contents('test.txt').$appendString."\n";
$iterations = 1000;

$start = microtime(true);
for ($i=0; $i<$iterations; $i++)
    file_put_contents('test.txt', $log, LOCK_EX);
$end=microtime(true);

$time = ($end*1000 - $start*1000) / $iterations;
echo 'Time : '.$time.'ms'. "\n";

$log=$appendString."\n";

$start = microtime(true);
for ($i=0; $i<$iterations; $i++)
    file_put_contents('test.txt', $log, LOCK_EX|FILE_APPEND);
$end=microtime(true);

$time = ($end*1000 - $start * 1000) / $iterations;
echo 'Time : '.$time.'ms' . "\n";

在窗户上:

Time : 0.22101293945313ms
Time : 0.039001953125ms

PHP 5.5.3 (cli) (built: Aug 20 2013 16:45:40)
Copyright (c) 1997-2013 The PHP Group
Zend Engine v2.5.0, Copyright (c) 1998-2013 Zend Technologies
    with Zend OPcache v7.0.3-dev, Copyright (c) 1999-2013, by Zend Technologies

在 Linux 上:

Time : 7.6823303222656ms
Time : 0.008222900390625ms

PHP 5.4.4-14+deb7u4 (cli) (built: Aug 23 2013 14:37:41)
Copyright (c) 1997-2012 The PHP Group
Zend Engine v2.4.0, Copyright (c) 1998-2012 Zend Technologies

这些数字看起来很合理,即使有 2 个不同的系统,因为在第一个循环中我们必须编写大字符串,而在第二个循环中只有一小部分附加到它,我们正在使用迭代来计算平均结果

结论:正如预期的那样 - 附加到文件比重写整个文件更快,至少因为需要的磁盘 IO 量要少得多

于 2013-11-01T20:03:46.823 回答
4

Phpfopen调用open系统调用,O_TRUNC这意味着它在以非附加模式写入之前截断文件。这种截断需要时间,并使其变慢。

在截断发生之后,在实际内容到达之前,您会看到空文件。

strace您可以在命令行中验证这一点。

于 2013-10-29T14:06:34.100 回答