用微时间测量持续时间随机结果为零
Measuring a duration with microtime results randomly in zero
我有一个这样的循环:
<?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) 命令的行,则没有零持续时间。
系统设置
- PHP 7.0 与 FPM
- nginx 1.10.3
- Ubuntu 16.04
我是 运行 CLI 上的循环并通过浏览器调用它。
数组中的 101 项对于聪明的 php 来说足够小,因为它有 static optimization 的技巧和强大的 cpu.
如果您想看到 0-s 消失了,那么生成 1000 个项目:
for ($i = 1; $i <= 1000; $i++) {
$haystack[] = substr(md5(microtime()),rand(0,26), 1);
}
P.S。我已经使用 7.1 和 5.6 检查了您的代码,因此存在很大差异:
除了@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>";
我添加了一个 运行dom "fake feature"。随机 25% 的迭代不应该 return 一个肯定的搜索结果。并且在 运行dom 50% 的迭代中,针将被放置在大海捞针的中间而不是末端。
我针对不同的设置(迭代、数组长度)多次运行这个脚本,最后我得到了大约 225.000 个结果行。快速添加一个小枢轴 table 显示,其中 PHP (7.0.32 fpm 和 CPU (Intel(R) Xeon(R) CPU E5-2680 v3 @ 2.50 GHz) 达到极限:
数字是毫秒/1000,所以即使是困难的(如 500.000 个键,1.000 次迭代)也需要 0,000000953674 微秒 - 感谢优化。厉害了。
有趣的是:最短持续时间(如果不是“0”)是相同的 (0,000953674) 或 加倍 (0,000001907349),即使是不同的迭代!所以,我的假设是,但这是非常幼稚的想法,如果我 运行 使用更大的数组或更多迭代进行测试,下一个即将到来的最小值将是 0.00000381469 微秒.
正如您也看到的,正如 num8er 已经指出的那样,优化的潜力越大,工作越难。
10 次爬行长度为 50.000 个键的数组比 100 或 1.000 次迭代还要慢。在 1.000 次迭代中,超过 10% 的结果是在 "optimized" 时间内交付的。
最后,我想指出,针是在大海捞针的中间,还是在大海捞针的尽头,似乎没有什么区别。下一个图表显示了搜索 500.000 键数组时 10、100 和 1.000 次迭代的最小持续时间。如您所见,最小值始终是 "magical" 0,000000953674:
不用说,每次迭代 return 都是正确的结果。因此,in_array() 从来没有 return 得到肯定的结果,当它爬行到没有针的大海捞针阵列时。
这可能不会为 PHP 优化功能添加更深入的技术细节,但我想看到此功能的影响很有趣。
我有一个这样的循环:
<?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) 命令的行,则没有零持续时间。
系统设置
- PHP 7.0 与 FPM
- nginx 1.10.3
- Ubuntu 16.04
我是 运行 CLI 上的循环并通过浏览器调用它。
数组中的 101 项对于聪明的 php 来说足够小,因为它有 static optimization 的技巧和强大的 cpu.
如果您想看到 0-s 消失了,那么生成 1000 个项目:
for ($i = 1; $i <= 1000; $i++) {
$haystack[] = substr(md5(microtime()),rand(0,26), 1);
}
P.S。我已经使用 7.1 和 5.6 检查了您的代码,因此存在很大差异:
除了@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>";
我添加了一个 运行dom "fake feature"。随机 25% 的迭代不应该 return 一个肯定的搜索结果。并且在 运行dom 50% 的迭代中,针将被放置在大海捞针的中间而不是末端。 我针对不同的设置(迭代、数组长度)多次运行这个脚本,最后我得到了大约 225.000 个结果行。快速添加一个小枢轴 table 显示,其中 PHP (7.0.32 fpm 和 CPU (Intel(R) Xeon(R) CPU E5-2680 v3 @ 2.50 GHz) 达到极限:
数字是毫秒/1000,所以即使是困难的(如 500.000 个键,1.000 次迭代)也需要 0,000000953674 微秒 - 感谢优化。厉害了。
有趣的是:最短持续时间(如果不是“0”)是相同的 (0,000953674) 或 加倍 (0,000001907349),即使是不同的迭代!所以,我的假设是,但这是非常幼稚的想法,如果我 运行 使用更大的数组或更多迭代进行测试,下一个即将到来的最小值将是 0.00000381469 微秒.
正如您也看到的,正如 num8er 已经指出的那样,优化的潜力越大,工作越难。
10 次爬行长度为 50.000 个键的数组比 100 或 1.000 次迭代还要慢。在 1.000 次迭代中,超过 10% 的结果是在 "optimized" 时间内交付的。
最后,我想指出,针是在大海捞针的中间,还是在大海捞针的尽头,似乎没有什么区别。下一个图表显示了搜索 500.000 键数组时 10、100 和 1.000 次迭代的最小持续时间。如您所见,最小值始终是 "magical" 0,000000953674:
不用说,每次迭代 return 都是正确的结果。因此,in_array() 从来没有 return 得到肯定的结果,当它爬行到没有针的大海捞针阵列时。
这可能不会为 PHP 优化功能添加更深入的技术细节,但我想看到此功能的影响很有趣。