Время выполнения итераций постоянно растёт

Добрый вечер дорогие пользователи,
Нужна ваша помощь, я написал, грубо говоря, воркер, который берёт данный из файла используя следю команду tail -n+x path/to/file | head -n50, но при каждой повторной итераций время выполнения скрипта увеличивается

Пример кода:

$p = 'UploadFiles/million_test.txt';
$l = 0;
$i = 0;
$start = microtime(true);
do {
    $command = "tail -n+$l $p | head -n50";
    exec($command, $data);

    $count = count($data);
    if ($count == 0) {
        die;
    }
    $i++;
    $l += 500;

    if ($i % 100 == 0) {
        file_put_contents(
            'test.txt',
            "$l [$count] =>" . round((microtime(true) - $start), 2) .
            PHP_EOL,
            FILE_APPEND
        );
        $start = microtime(true);
    }
    unset($data);
} while ($count > 0);

Данные выполнения скрипта

50000 [50] =>0.71 100000 [50] =>0.9 150000 [50] =>1.09 200000 [50] =>1.19 250000 [50] =>1.35 300000 [50] =>1.44 350000 [50] =>1.58 400000 [50] =>1.66 450000 [50] =>1.65

Как вы можете видеть, спустя пару итераций время выполнение скрипта увеличивалось в 2 раза.
Может кто-то знает что я делаю не так?
Или хотя-бы дайте намёк что на почитать, буду очень плагодарен.

В файле million_test.txt около 12 миллионов записей.


Ответы (2 шт):

Автор решения: newman

В общем-то это все объяснимо. Вероятней всего время итерации увеличивается из-за того что дольше работает команда tail. Т.е. тут проблема не вашем коде, а в том как tail работает.

Т.е. когда вы "просите" выдать вам последние 500 строк из файла, то команда считывает эти 500 строк и выводит. Когда вы просите выдать следующие 500 строк, то команда считывает 1000 строк и выводит их, а потом через head вы берете из них только пятьсот.

На следующей итерации tail считывает уже 1500 строк. И т.д. и т.п. Чем ближе к началу файла, тем больше строк нужно считать и выдать, тем дольше работает команда.

В данной реализации с этим ничего не поделать. Не совсем понятно какую вы задачу решаете. Но возможно более оптимально и быстро будет открыть этот файл средствами PHP и построчно его прочитать за один раз. И разбить на блоки, если это нужно. Или сделать что-то еще.

→ Ссылка
Автор решения: Максим
$command = "tail -n+$l $p | head -n50";
exec($command, $data);

команда считывает из файла все(-n+$l) строк, а потом берет верхнюю их часть(-n50) сам подход очень медленный. file($p) для этого подойдет много лучше, ниже сравнительный тест по скорости чтения сгенерированого файла на 1м строк

весь файл прочитан функцией file($p) за 0.01сек 

далее произведено чтение файла по частям при помощи exec("trail ....")
Array
(
    [50_5000] => 0.03
    [50_10000] => 0.03
    [50_15000] => 0.03
    [50_20000] => 0.03
    [50_25000] => 0.03
    [50_30000] => 0.03
    [50_35000] => 0.04
    [50_40000] => 0.04
    [50_45000] => 0.04
    [50_50000] => 0.04
    [50_55000] => 0.04
    [50_60000] => 0.04
    [50_65000] => 0.04
    [50_70000] => 0.04
    [50_75000] => 0.05
    [50_80000] => 0.05
    [50_85000] => 0.05
    [50_90000] => 0.05
    [50_95000] => 0.05
    [50_100000] => 0.05
)
→ Ссылка