Perl быстрее, чем удар?

По-моему, "лучшим" решением является то, которое может быть считано другим программистом (или исходным программистом два года спустя) без обильных комментариев. Можно хотеть самое быстрое или самое умное решение, которое некоторые уже предоставили, но я предпочитаю удобочитаемость по уму любое время.

unsigned int bitCount (unsigned int value) {
    unsigned int count = 0;
    while (value > 0) {           // until all bits are zero
        if ((value & 1) == 1)     // check lower bit
            count++;
        value >>= 1;              // shift bits, removing lower bit
    }
    return count;
}

, Если Вы хотите больше скорости (и принятие Вас документируют его хорошо для выручения преемников), Вы могли использовать поиск по таблице:

// Lookup table for fast calculation of bits set in 8-bit unsigned char.

static unsigned char oneBitsInUChar[] = {
//  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F (<- n)
//  =====================================================
    0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, // 0n
    1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, // 1n
    : : :
    4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, // Fn
};

// Function for fast calculation of bits set in 16-bit unsigned short.

unsigned char oneBitsInUShort (unsigned short x) {
    return oneBitsInUChar [x >>    8]
         + oneBitsInUChar [x &  0xff];
}

// Function for fast calculation of bits set in 32-bit unsigned int.

unsigned char oneBitsInUInt (unsigned int x) {
    return oneBitsInUShort (x >>     16)
         + oneBitsInUShort (x &  0xffff);
}

, Хотя они полагаются на определенные размеры типа данных, таким образом, они не то, что портативны. Но, так как много оптимизаций производительности не являются портативными так или иначе, который не может быть проблемой. Если бы Вы хотите мобильность, я придерживался бы читаемого решения.

11
задан chaos 27 August 2009 в 20:19
поделиться

10 ответов

Обновленный сценарий на основе комментария Брента: Этот не тестировался.

#!/usr/bin/perl

use strict;
use warnings;

my %months = (
    jan => 1, feb => 2,  mar => 3,  apr => 4,
    may => 5, jun => 6,  jul => 7,  aug => 8,
    sep => 9, oct => 10, nov => 11, dec => 12,
);

while ( my $line = <> ) {
    my $ts = substr $line, 0, 15;
    next if parse_date($ts) lt '0201100543';
    last if parse_date($ts) gt '0715123456';
    print $line;
}

sub parse_date {
    my ($month, $day, $time) = split ' ', $_[0];
    my ($hour, $min, $sec) = split /:/, $time;
    return sprintf(
        '%2.2d%2.2d%2.2d%2.2d%2.2d',
        $months{lc $month}, $day,
        $hour, $min, $sec,
    );
}


__END__

Предыдущий ответ для справки: Какой формат у файла? Вот короткий сценарий, который предполагает, что первый столбец является меткой времени, и печатает только строки, которые имеют метки времени в определенном диапазоне. Также предполагается, что отметки времени отсортированы. В моей системе требовалось около секунды, чтобы отфильтровать 900 000 строк из миллиона:

#!/usr/bin/perl

use strict;
use warnings;

while ( <> ) {
    my ($ts) = split;
    next if $ts < 1247672719;
    last if $ts > 1252172093;
    print $ts, "\n";
}

__END__
12
ответ дан 3 December 2019 в 00:43
поделиться

Основываясь на имеющемся у вас шелл-коде, с множественными вызовами tail / head, я бы сказал абсолютно Perl мог бы быть быстрее. C мог бы быть даже быстрее, но время разработки, вероятно, того не стоит, поэтому я буду придерживаться Perl. (Я говорю «мог бы», потому что вы можете писать сценарии оболочки на Perl, и я видел достаточно таких, чтобы передернуться. Это, очевидно, не даст того преимущества в скорости, которое вам нужно.)

Perl имеет более высокую стоимость запуска, или так утверждается. Честно говоря, никогда не замечал. Если ваша альтернатива - сделать это на Java, Perl не требует затрат на запуск. По сравнению с Башом я просто не заметил. Что я заметил, так это то, что по мере того, как я ухожу от вызова всех специализированных инструментов Unix, которые хороши, когда у вас нет альтернатив, и делаю все это в одном процессе, скорость возрастает. Накладные расходы на создание новых процессов в Unix не такие серьезные, как в Windows, но они все же не совсем незначительны, поскольку вам нужно каждый раз повторно инициализировать библиотеку времени выполнения C (libC), анализировать аргументы, открывать файлы (возможно) и т. д. В Perl вы в конечном итоге используете огромные объемы памяти, когда передаете все в списке или что-то еще, но все это находится в памяти, поэтому это быстрее. И многие из инструментов, к которым вы привыкли, либо встроены ( map / grep , регулярные выражения), либо доступны в модулях на CPAN. Хорошая комбинация из них позволит легко выполнить работу.

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

5
ответ дан 3 December 2019 в 00:43
поделиться

Вы почти наверняка ощутите огромный выигрыш в скорости от написания вашего скрипта на Perl, просто отключив чтение файла, когда вы передадите вашу вторую временную метку.

В общем, да; сценарий bash любой сложности, если только он не является действительно удивительным волшебством, может быть легко проигран сценарием Perl для эквивалентных входов и выходов.

18
ответ дан 3 December 2019 в 00:43
поделиться

Perl до абсурда быстрее, чем Bash. А что касается манипуляций с текстом, вы можете добиться более высокой производительности с Perl, чем с C, если только вы не потратите время на написание сложных алгоритмов. Конечно, для простых вещей C может быть непревзойденным.

Тем не менее, если ваш сценарий "bash" не зацикливается, а просто вызывает другие программы, тогда не будет никакого выигрыша. Например, если ваш сценарий выглядит как « cat X | grep Y | tr -f 3-5 | sort | uniq », то большая часть времени уходит на cat, grep, tr, sort и uniq. , НЕ на Bash.

Вы повысите производительность, если в сценарии есть какой-либо цикл или если вы сохраните несколько чтений одного и того же файла.

Вы говорите, что вы сокращаете материал между двумя отметками времени в файле. Допустим, ваш сценарий Bash выглядит так:

LINE1=`grep -n TIMESTAMP1 filename | head -1 | cut -d ':' -f 1`
LINE2=`grep -n TIMESTAMP2 filename | head -1 | cut -d ':' -f 1`
tail +$LINE1 filename | head -$(($LINE2-$LINE1))

Тогда вы увеличите производительность, потому что вы читаете весь файл три раза: по одному разу для каждой команды, где появляется «имя файла». В Perl вы бы сделали что-то вроде этого:

my $state = 0;
while(<>) {
  exit if /TIMESTAMP2/;
  print $_ if $state == 1;
  $state = 1 if /TIMESTAMP1/;
}

Это прочитает файл только один раз и также остановится, как только вы прочитаете TIMESTAMP2. Поскольку вы обрабатываете несколько файлов, вы должны использовать «last» или «break» вместо «exit», чтобы сценарий мог продолжить обработку файлов.

В любом случае, увидев ваш сценарий, я уверен, что вы получить много, переписав его на Perl. Несмотря на циклы, связанные с именами файлов (скорость которых БУДЕТ улучшена, но, вероятно, незначительна), для каждого файла, который не находится полностью внутри или вне области видимости, вы делаете:

  1. Прочтите ВЕСЬ файл для подсчета строк!
  2. Сделайте несколько хвосты в файле
  3. Закончить "головой" или "хвостом" файл еще раз

Кроме того, держите хвосты. Каждый раз, когда вы это делаете, какой-то фрагмент кода считывает эти данные. Некоторые из этих строк читаются до 10 и более раз!

27
ответ дан 3 December 2019 в 00:43
поделиться

это зависит от того, как написан ваш сценарий bash. если вы не используете awk для синтаксического анализа файла журнала, а вместо этого используете цикл while в bash, то изменение его на awk повысит скорость.

2
ответ дан 3 December 2019 в 00:43
поделиться

Я согласен с тем, что переход от сценария только для bash к Perl (или даже awk, если среда Perl недоступна) может дать выигрыш в скорости, если оба они одинаково хорошо написаны.

Однако, если бы отрывок можно было сформировать с помощью сценария bash, который создает параметры для, а затем вызывает grep с регулярным выражением, то это может быть быстрее, чем «чистый» сценарий.

1
ответ дан 3 December 2019 в 00:43
поделиться

Я бы профилировал все три решения и выбрал лучшее с точки зрения начальной скорости запуска, скорости обработки и использования памяти.

Что-то вроде Perl / Python / Ruby может быть не самым быстрым, но на этих языках можно быстро развиваться - намного быстрее, чем на C и даже на Bash.

2
ответ дан 3 December 2019 в 00:43
поделиться

В вашем сценарии bash укажите следующее:

perl -ne "print if /$FROM/../$TO/" $LOGFILES

$ FROM и $ TO на самом деле являются регулярными выражениями для вашего времени начала и окончания.

Они являются инклюзивными, поэтому вы можете указать 2009-06-14 23:59:59 в качестве времени окончания, поскольку 2009-06-15 00:00:00 будет включать транзакции в полночь.

1
ответ дан 3 December 2019 в 00:43
поделиться

bash на самом деле читает файл построчно, поскольку он интерпретирует его на лету (о чем вы будете болезненно осведомлены, если когда-нибудь измените bash , пока он все еще работает), а не предварительно загружать и анализировать все сразу. Так что да, Perl, как правило, будет намного быстрее, если вы будете делать то, чего обычно не делаете в bash .

1
ответ дан 3 December 2019 в 00:43
поделиться

Что ж, bash интерпретируется построчно во время работы и зависит от вызова множества внешних программ (в зависимости от того, что вы хотите сделать). Вам часто приходится использовать временные файлы в качестве промежуточного хранилища для наборов результатов. Он (оболочка) изначально был разработан для взаимодействия с системой и автоматизации последовательностей cmd (файлов оболочки).

Perl больше похож на C, он в значительной степени самодостаточен с огромной библиотекой бесплатного кода и скомпилирован, поэтому работает намного быстрее , например, скорость C составляет около 80-90%, но легче программировать (например, переменные размеры являются динамическими). ​​

0
ответ дан 3 December 2019 в 00:43
поделиться
Другие вопросы по тегам:

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