Измерение длительности с помощью микротайма приводит к случайным результатам в ноль - PullRequest
0 голосов
/ 04 декабря 2018

У меня такой цикл:

<?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,192092895507812500001,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

IЯ запускаю цикл на CLI и вызываю его через браузер.

Ответы [ 2 ]

0 голосов
/ 05 декабря 2018

Просто в дополнение к ответу @ 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% итераций игла будет размещена в середине стога сена, а не в конце.Я запускал этот скрипт несколько раз для разных настроек ( итерации , длина массива ), и в итоге у меня было около 225.000 строк результатов.Быстрое добавление небольшой сводной таблицы показывает, где PHP (7.0.32 fpm и CPU (Intel (R) Xeon (R) CPU E5-2680 v3 @ 2.50GHz) достигает предела):

minimum durations when searching arrays, lengths vs iterations

Числа - это миллисекунды / 1000, поэтому даже сложные (например, 500 000 ключей, 1000 итераций) занимали 0,000000953674 микросекунд - благодаря оптимизации. Это впечатляет.

Что также интересно: минимальные длительности, если не «0», являются одинаковыми ( 0,000953674 ) или , удвоенными ( 0,000001907349 ), дажедля разных итераций! Итак, я предполагаю, но это довольно наивное мышление. Если бы я запустил тест с большими массивами или большим количеством итераций, следующий предстоящий минимум составил бы 0,00000381469 микросекунд .

Как вы также можете видеть, и, как уже говорилось в num8er, потенциал оптимизации возрастает по мере усложнения задания.

Top 10 of quickest durations for 50.000-key-arrays

10 раз сканирование массивов с помощьюдлина 50 000 клавиш даже медленнее, чем 100 или 1,000 итераций.Из 1.000 итераций более 10% результатов были получены в «оптимизированное» время.

Наконец, я хочу отметить, что, похоже, нет никакой разницы, если игла находится в середине стога сена или в конце.Следующая диаграмма показывает минимальные длительности для 10, 100 и 1.000 итераций при поиске в 500.000 ключевых массивов.Как видите, minium всегда является «магическим» 0,000000953674:

Minimum durations for 500.000-key-arrays with different needle positions

Нет необходимости говорить, что каждая итерация возвращает правильный результат.Так, in_array () никогда не возвращал положительный результат, когда он сканировал массив стога сена, не содержащий иглы.

Это, возможно, не добавляет более глубоких технических подробностей к функции оптимизации PHP, но, тем не менее, я думаю, интересно увидеть влияние этой функции.

0 голосов
/ 04 декабря 2018

101 элементов в массиве достаточно мал для умного php с статической оптимизацией трюками и мощным процессором.

Если вы хотите увидеть, что 0 пропали, генерируйте 1000 элементов:

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

PS Я проверил ваш код, используя 7.1 и 5.6, поэтому есть большие различия:

php7.1 vs php5.6

...