PHP скрипт становится все медленнее (программа для чтения файлов) - PullRequest
5 голосов
/ 15 августа 2010

У меня есть сценарий, который при установке против таймера становится все медленнее.Это довольно просто, поскольку все, что он делает - читает строку, проверяет, затем добавляет ее в базу данных и затем переходит к следующей строке.

Вот результат, который постепенно ухудшается:

Record: #1,001 Memory: 1,355,360kb taking 1.84s
Record: #1,001 Memory: 1,355,360kb taking 1.84s
Record: #2,002 Memory: 1,355,192kb taking 2.12s
Record: #3,003 Memory: 1,355,192kb taking 2.39s
Record: #4,004 Memory: 1,355,192kb taking 2.65s
Record: #5,005 Memory: 1,355,200kb taking 2.94s
Record: #6,006 Memory: 1,355,376kb taking 3.28s
Record: #7,007 Memory: 1,355,176kb taking 3.56s
Record: #8,008 Memory: 1,355,408kb taking 3.81s
Record: #9,009 Memory: 1,355,464kb taking 4.07s
Record: #10,010 Memory: 1,355,392kb taking 4.32s
Record: #11,011 Memory: 1,355,352kb taking 4.63s
Record: #12,012 Memory: 1,355,376kb taking 4.90s
Record: #13,013 Memory: 1,355,200kb taking 5.14s
Record: #14,014 Memory: 1,355,184kb taking 5.43s
Record: #15,015 Memory: 1,355,344kb taking 5.72s

Файл, к сожалению, составляет около ~ 20 Гб, поэтому я, вероятно, умру к тому времени, когда все это будет прочитано со скоростью увеличения.Код (в основном) ниже, но я подозреваю, что это как-то связано с fgets (), но я не уверен, что.

    $handle = fopen ($import_file, 'r');

    while ($line = fgets ($handle))
    {
        $data = json_decode ($line);

        save_record ($data, $line);
    }

Заранее спасибо!

РЕДАКТИРОВАТЬ:

Закомментирование 'save_record ($ data, $ line);'кажется, ничего не делает.

Ответы [ 4 ]

1 голос
/ 18 августа 2010

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

$lines = exec("wc -l $filename");
for($i=1; $i <= $lines; $i++) {
   $line = exec('sed \''.$i.'!d\' '.$filename);

   // do what you want with the record here
}

Я бы не советовал делать это с файлами, которым нельзя доверять, но он работает быстро, так как использует одну запись за раз, используя систему,Надеюсь, это поможет.

0 голосов
/ 05 апреля 2011

Я нашел этот вопрос, пытаясь найти способ быстрее пройти через текстовый файл 96G. Сценарий, который я изначально написал, занял 15 часов, чтобы достичь 0,1% ...

Я попробовал некоторые из предложенных здесь решений, используя stream_get_line, fgets и exec для sed. В итоге у меня был другой подход, которым я поделился с кем-то еще, если бы остановился на этом вопросе.

Разделить файл вверх! : -)

В моем окне freebsd (также существует для linux и других) у меня есть утилита командной строки с именем 'split'.

usage: split [-l line_count] [-a suffix_length] [file [prefix]]
       split -b byte_count[K|k|M|m|G|g] [-a suffix_length] [file [prefix]]
       split -n chunk_count [-a suffix_length] [file [prefix]]
       split -p pattern [-a suffix_length] [file [prefix]]

Итак, я побежал:

split -l 25000 -a 3 /data/var/myfile.log /data/var/myfile-log/

Затем я получил 5608 файлов в каталоге / data / var / myfile-log /, которые затем можно было обработать по одной команде:

php -f do-some-work.php /data/var/myfile-log/*
0 голосов
/ 17 августа 2010

Хорошо, проблема с производительностью. Очевидно, что что-то становится квадратичным, когда это не должно, или, более точно, что-то, что должно быть постоянным временем, кажется линейным по количеству записей, рассматриваемых до сих пор. Первый вопрос - каков минимальный кусок кода, который демонстрирует проблему. Я хотел бы знать, если вы получаете такое же проблемное поведение, когда вы закомментируете все, кроме чтения файла построчно. Если так, то вам нужен язык без этой проблемы. (Их много.) В любом случае, как только вы увидите ожидаемую характеристику времени, добавляйте операторы один за другим, пока время не станет плохим, и вы не выявите проблему.

Вы инструктировали то или иное, чтобы получить время. Убедитесь, что они не могут вызвать проблемы, выполнив их в одиночку 15000 раз или около того.

0 голосов
/ 15 августа 2010

http://php.net/manual/en/function.fgets.php

Согласно комментарию Ли Пурди, существует проблема с производительностью больших файлов с fgets. Если ваши объекты JSON больше его тестовых строк, вы можете ограничить их намного быстрее

используйте http://php.net/manual/en/function.stream-get-line.php и укажите ограничение длины

...