Задать вопрос
@maiskiykot
Free coder

Как ускорить чтение большого архива gz?

Есть файлы на десятки миллионов строк. Делаю для себя поиск по ним. Проблема в чем - если, его раскрывать, то даже винда начинает притормаживать и вываливаются приложения. Пошел по пути чтения с помощью php. Собрал с миру по нитке такой вот код
ini_set('memory_limit', '2048M');
  ini_set('max_execution_time', '3000');
  
 $z = gzopen($_POST['file'],'r') or die("can't open: $php_errormsg");
    $string = [];

    while ($line = gzgets($z,1024)) {
     
       if (preg_match("!".$_POST['request'][0]."[^0-9]!",$line))
       $string[] = $line;
    
    }
      //далее обрабатываю $string.

Все бы ничего, но ищет минуты три инфу, а тот же Emeditor несколько секунд. Как оптимизировать поиск в пределах php? Всем спасибо!
  • Вопрос задан
  • 167 просмотров
Подписаться 1 Средний 6 комментариев
Пригласить эксперта
Ответы на вопрос 4
Stalker_RED
@Stalker_RED
zgrep -i mySearchStr myFile.txt.gz
Ответ написан
glaphire
@glaphire Куратор тега PHP
PHP developer
1) вижу в коде $_POST и получение файла из запроса, не проще ли написать консольный скрипт, который просто читает файл по указанному пути?
2) можно использовать генератор, чтобы не грузить память файлом
https://www.php.net/manual/ru/language.generators....
https://riptutorial.com/php/example/5441/reading-a...
Ответ написан
@rPman
на php анализ логов будет очень медленным, я переписывал на c++ и получал до 10крат ускорение (можно и больше, все зависит от логики анализа, а при использовании clang llvm еще 2х, например парсинг json ускоряется буквально на глазах, пока llvm собирает статистику исполнения), у тебя основная нагрузка именно тут.

так же пользуйся многопоточностью, например готовые консольные утилиты и пайпы, запуская их из своей программы:

pigz -dkc dump.log.gz | grep -e 'регулярное выражение' | программа_анализирующая_итоговые_строки

тут дополнительно gzip заменен на pigz, можно скачать для windows даст кратно ускорение на распаковку за счет многопоточности.

upd: замени gzip на zstd, вот уж где ускорение получишь, и бонусом еще несколько процентов уменьшения размера архивов.
Ответ написан
@ksnk
Читать нужно не по строкам, а блоками, килобайт по 40. Просто проверь - чтение блоками всего файла или чтение построчное gzgets. Вот искать в таких блоках сложнее - нужно гарантировать что найденный кусок не попадет на границу буфера чтения. Для этого, можно последнюю "строку" блока сохранять и копировать в следующий блок.
Читать загзипованые файлы удобнее, imho, обычными файловыми операциями fread, feof вот только открывать его придется gzopen. Как нибудь так...
if (preg_match('/\.gz$/', $name)) {
                $_handle = fopen($name, "rb");
                fseek($_handle, filesize($name) - 4);
                $x = unpack("L", fread($_handle, 4));
                $this->finish = $x[1];
                fclose($_handle);
                $handle = gzopen(
                    $handle, 'r'
                );
            } else {
                $this->finish = filesize($name);
                $handle = fopen($name, 'r');
            }
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы