【问题标题】:Measuring a duration with microtime results randomly in zero用微时间测量持续时间随机结果为零
【发布时间】:2018-12-03 21:52:46
【问题描述】:

我有一个这样的循环:

<?php
ini_set('memory_limit', '16024M');
ini_set('set_time_limit', 9999);
ini_set('max_execution_time', 9999);
ini_set('display_errors',  TRUE);
ini_set('error_reporting',  E_ALL);

for ($k = 1; $k <= 50; $k++) {

    $haystack = array();

    for ($i = 1; $i <= 100; $i++) {

        $randomChar = substr(md5(microtime()),rand(0,26), 1);

        $haystack[] = $randomChar;

    }

    $haystack[] = 'X';

    $startTime = microtime(true);

    // sleep(0);

    $result = in_array('X', $haystack);

    $endTime = microtime(true);

    echo number_format(1000000 * ($endTime - $startTime), 20, ",", " ") . ' ';

 }

这些是输出的前几行:

1,90734863281250000000 0,95367431640625000000 1,19209289550781250000 1,90734863281250000000 1,19209289550781250000 0,95367431640625000000 0,95367431640625000000 1,90734863281250000000 0,95367431640625000000 20,02716064453125000000 0,95367431640625000000 1,19209289550781250000 0,95367431640625000000 0,95367431640625000000 0,00000000000000000000 0,95367431640625000000 0,95367431640625000000 0,95367431640625000000 0,00000000000000000000 0,95367431640625000000 0,00000000000000000000

如您所见,有几行说明持续时间为“0”——这实际上是不可能的。如果我取消注释包含 sleep(0) 命令的行,则没有零持续时间。

系统设置

  • 带有 FPM 的 PHP 7.0
  • nginx 1.10.3
  • Ubuntu 16.04

我在 CLI 上运行循环并通过浏览器调用它。

【问题讨论】:

  • 您是否在 Windows 上运行您的网络服务器?
  • 不,它在 Ubuntu 16.04 上运行
  • error_reporting 调到最大,并确保display errors 已打开。
  • error_reporting 等。人。已激活,将此添加到代码中
  • 很奇怪。 3v4l 在所有版本的 PHP7 中都表现出相同的行为。 3v4l.org/oL6RI

标签: php duration microtime


【解决方案1】:

数组中的 101 项对于智能 php 来说足够小了,它具有 static optimization 技巧和强大的 cpu。

如果你想看到 0-s 消失了,那么生成 1000 个项目:

for ($i = 1; $i <= 1000; $i++) {
    $haystack[] = substr(md5(microtime()),rand(0,26), 1);
}

附:我使用 7.1 和 5.6 检查了您的代码,因此存在很大差异:

【讨论】:

  • 谢谢。这只是我完整脚本的一部分,实际上我使用的数字要大得多,请在此处查看完整脚本:gist.github.com/nickyreinert/fb7d195db011287730f9c6a1ab7885a5
  • @n.r.我已经在 7.1 php 上执行了你的脚本我没有得到零,我也等了一会儿 - 没有零
  • 好的,我现在明白你的意思了。实际上,我也是这样做的,使用 100.000 个键的数组运行脚本。我想知道,为什么较小的数组的持续时间为 0。那么——“静态优化”才是最终的解释?
  • 我认为是的,幻灯片:slideshare.net/nikita_ppv/… 和 pdf 解释了他们所做的改进:biagiocosenza.com/papers/PopovCC17.pdf
  • 但是我仍然想知道两件事:为什么其他循环不受影响以及为什么简单的 sleep(0) 会对这种行为产生负面影响?我会调查的...无论如何谢谢!
【解决方案2】:

除了@num8er 答案,这似乎是答案,我试图找出更多,因为这真的让我有些不眠之夜。我稍微改进了上面的脚本并运行了一些额外的测量:

  ini_set('memory_limit', '16024M');
  ini_set('set_time_limit', 9999);
  ini_set('set_time_limit', -1);
  ini_set('max_execution_time', 9999);
  ini_set('max_execution_time', -1);
  ini_set('display_errors',  TRUE);
  ini_set('error_reporting', E_ALL);

echo "<table>";
echo "<tr>";
    echo "<th>duration</th>";
    echo "<th>position</th>";
    echo "<th>fake</th>";
    echo "<th>found</th>";
    echo "<th>optimized</th>";
echo "</tr>";

$endPosition = TRUE;

$fake = false;

for ($k = 1; $k <= 10000; $k++) {

    $haystack = array();

    for ($i = 1; $i <= 50000; $i++) {

        $randomChar = substr(md5(microtime()),rand(0,26), 1);

        $haystack[] = $randomChar;

    }

    if ($fake) {

        $needle = NULL;


    } else {

        if ($endPosition) {

            $needle = $haystack[sizeof($haystack) - 1];

        } else {

            $needle = $haystack[floor(sizeof($haystack)/ 2)];

        }

    }

    $startTime = microtime(true);

    //sleep(0);

    $result = in_array($needle, $haystack);

    $endTime = microtime(true);

    $duration = ($endTime - $startTime);

    echo "<tr>";
        echo "<td>";
        echo number_format($duration, 30, ",", " ");
        echo "</td>";
        echo "<td>";
        echo ($endPosition) ? "end": "middle";
        echo "</td>";
        echo "<td>";
        echo ($fake) ? "fake": "no fake";
        echo "</td>";
        echo "<td>";
        echo ($result) ? "found": "not found";
        echo "</td>";
        echo "<td>";
        echo ($duration == 0) ? "optimized": "---";
        echo "</td>";
    echo "</tr>";

    $endPosition = (rand(0,100) < 50) ? TRUE : FALSE;
    $fake = (rand(0,100) < 25) ? TRUE : FALSE;

}

echo "</table>";

我添加了一个随机的“假功能”。随机 25% 的迭代不应返回正搜索结果。在随机 50% 的迭代中,针将被放置在干草堆的中间,而不是在最后。 我针对不同的设置(iterationsarray length)运行了这个脚本几次,最后我得到了大约 225.000 个结果行。快速添加一个小数据透视表,显示 PHP(7.0.32 fpm 和 CPU(Intel(R) Xeon(R) CPU E5-2680 v3 @ 2.50GHz)达到极限:

数字是毫秒/1000,因此即使是最困难的数字(例如 500.000 个键,1.000 次迭代)也需要 0,000000953674 微秒 - 这要归功于优化。这令人印象深刻。

还有什么有趣的:如果不是“0”,最短持续时间是相同的 (0,000953674) 或 加倍 (0,000001907349),即使是不同的迭代!所以,我的假设是,但这是非常幼稚的想法,如果我用更大的数组或更多的迭代运行测试,下一个即将到来的最小值将是 0.00000381469 微秒

您也可以看到,正如 num8er 已经指出的那样,优化的潜力越大,工作就越难。

10 次爬取长度为 50.000 个键的数组甚至比 100 或 1.000 次迭代还要慢。在 1.000 次迭代中,超过 10% 的结果是在“优化”时间内交付的。

最后,我想指出,如果是在干草堆的中间,还是在最后,似乎没有什么区别。下图显示了搜索 500.000 键数组时 10、100 和 1.000 次迭代的最短持续时间。如您所见,最小值始终是“神奇”的 0,000000953674:

不用说,每次迭代都会返回正确的结果。因此,当 in_array() 爬取不包含针头的 haystack-array 时,它从未返回过肯定的结果。

这可能不会为 PHP 优化功能添加更深入的技术细节,但我想看看这个功能的影响会很有趣。

【讨论】:

    猜你喜欢
    • 2012-04-07
    • 1970-01-01
    • 1970-01-01
    • 2013-09-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多