Perl увеличение производительности при выполнении File IO - PullRequest
0 голосов
/ 18 апреля 2020

У меня есть скрипт, который берет список журналов из каталога Log и выполняет некоторые операции.

У меня возникла проблема с производительностью при выполнении этой операции. Потому что у меня большой набор log файлов, и мне нужно выполнить операцию над каждым из файлов. В настоящее время мой скрипт установлен в cron и работает каждый час. Поэтому я хочу переписать этот файл, читая logi c (@content) или мне нужно увеличить производительность этого скрипта, который может выполнять операции с файлами быстрее, чем текущий процесс.

Вот скрипт:

#/usr/bin/perl

use strict;
use warnings;
.
.

my $LogPath = "/path/to/log/file/";

my $list = `ls -1 $LogPath*.log`;

my @array_list = split(/\n/, $list);

foreach $file (@array_list){ 
    my $cat = `cat $file`;

    my @content = split(/\n/, $cat);

    foreach $line (@content) {
        ....
        #Doing some operation if the matching content found
        ....
        ....
    }
}

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

Ответы [ 3 ]

2 голосов
/ 18 апреля 2020

Начните с использования системных вызовов вместо внешних программ, чтобы получить необходимую информацию.

my $log_dir_qfn = "/path/to/log/file";

my $error = 0;
for my $log_qfn (quotemeta($log_dir_qfn) . "/*.log") {
   open(my $fh, '<', $log_qfn)
      or do {
         warn("Can't open \"$log_qfn\": $!\n");
         ++$error;
         next;
      };

   while ( my $line = <$fh> ) {
      ...
   }
}

exit(1) if $error;

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

0 голосов
/ 18 апреля 2020

Вы можете рассмотреть / протестировать, используя модуль

Файл :: Slurp (https://metacpan.org/pod/File :: Slurp )

Серьезно, не используйте внешний вызов команды в l oop - это снижает производительность!

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

0 голосов
/ 18 апреля 2020

Если вы выполняете некоторую фильтрацию, которую предлагает ваш комментарий в самом глубоком foreach, и вы игнорируете большинство строк в журналах, то вы можете попробовать заменить my $cat = `cat $file`; на my $cat = `grep PATTERN $file`;, чтобы хотя бы смягчить Perl памяти, если файлы большие. Может быть, даже такие большие, что они вызывают перестановку дисков из-за нехватки памяти, что и является вашей реальной проблемой с вашим perl кодом. Во многих, если не в большинстве версий grep, PATTERN также может быть регулярным выражением типа perl с параметром -P: grep -P 'REGEXP' file.

Если медлительность равна, например, 99% IO (чтение с диска и / или пишет, что вы можете узнать по time perl script.pl и посмотреть, если real из вывода time намного больше, чем другие), то, вероятно, вы мало что можете сделать, за исключением того, что ваша система может сделать сжатые файлы журнала. Иногда, если у вас медленный диск, может быть диск, смонтированный в сети, и быстрые процессоры, распаковка + обработка может быть быстрее, чем просто обработка несжатых файлов. Возможно, так: my $cat = ` zcat $file.gz | grep PATTERN `;

Также вы можете попробовать распараллелить с fork, добавив этот внешний for-l oop:

my $LogPath = "/path/to/log/file";
my $list = `ls -1 $LogPath/*.log`;
my $jobs=4; #split work into 4 jobs (splits work to up to 4 CPUs)
for my $job (1..$jobs){
  next if !fork;
  my $i=0;
  my @array_list = grep $i++ % $jobs == $job-1, #do only what this process should
                   split(/\n/, $list);
  foreach $file (@array_list){
    my $cat = `cat $file`;
    my @content = split(/\n/, $cat);
    foreach $line (@content) {
      ....
      #Doing some operation if the matching content found
      ....
      ....
    }
  }
  last;
}

(Кстати, for и foreach являются синонимами, не знаю, почему так много perl кодеров беспокоятся о четырех последних символах foreach)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...