Обработка текста - производительность Python и Perl

56

Вот мой perl и python script, чтобы сделать некоторую простую текстовую обработку из примерно 21 файла журнала каждый примерно от 300 КБ до 1 МБ (макс.) х 5 раз повторяется (всего 125 файлов, из-за журнала повторяется 5 раз).

Код Python (код изменен для использования скомпилированного re и с использованием re.I)

#!/usr/bin/python

import re
import fileinput

exists_re = re.compile(r'^(.*?) INFO.*Such a record already exists', re.I)
location_re = re.compile(r'^AwbLocation (.*?) insert into', re.I)

for line in fileinput.input():
    fn = fileinput.filename()
    currline = line.rstrip()

    mprev = exists_re.search(currline)

    if(mprev):
        xlogtime = mprev.group(1)

    mcurr = location_re.search(currline)

    if(mcurr):
        print fn, xlogtime, mcurr.group(1)

Код Perl

#!/usr/bin/perl

while (<>) {
    chomp;

    if (m/^(.*?) INFO.*Such a record already exists/i) {
        $xlogtime = $1;
    }

    if (m/^AwbLocation (.*?) insert into/i) {
        print "$ARGV $xlogtime $1\n";
    }

}

И на моем ПК оба кода генерируют точно такой же файл результата из 10 790 строк. И, вот сроки, сделанные на cygwin perl и python

User@UserHP /cygdrive/d/tmp/Clipboard
# time /tmp/scripts/python/afs/process_file.py *log* *log* *log* *log* *log* >
summarypy.log

real    0m8.185s
user    0m8.018s
sys     0m0.092s

User@UserHP /cygdrive/d/tmp/Clipboard
# time /tmp/scripts/python/afs/process_file.pl *log* *log* *log* *log* *log* >
summarypl.log

real    0m1.481s
user    0m1.294s
sys     0m0.124s

Первоначально для этой простой обработки текста потребовалось 10,2 секунды с использованием Python и всего 1,9 секунды с использованием Perl.

(UPDATE), но после скомпилированной версии python теперь она занимает 8,2 секунды на python и 1,5 секунды в perl. Тем не менее perl намного быстрее.

В любом случае, чтобы улучшить скорость Python вообще ИЛИ, очевидно, что вы, ребята, ребята, что Perl будет быстродействующим для простой обработки текста.

Кстати, это был не единственный тест, который я сделал для простой обработки текста... И каждый раз, когда я делаю исходный код, всегда всегда Perl выигрывает с большим отрывом. И ни разу Python не работал лучше для простого m/regex/ совпадения и печати. ​​

Спасибо за ваш вклад.

Пожалуйста, не предлагайте использовать C, С++, Assembly, другие варианты Python и т.д.

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

Итак, пожалуйста, предложите, как можно улучшить код, чтобы сопоставить результаты с perl.

ОБНОВЛЕНИЕ: 18OCT2012

Как и другие пользователи, Perl имеет свое место, а Python имеет свой.

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

Обратите внимание, что когда я говорю, что Perl выигрывает в производительности, сравниваются только стандартные Perl и Python... не прибегая к некоторым неясным модулям (неясный для обычного пользователя, как я), а также не вызывающий C, С++, сборные библиотеки от python или perl. У нас нет времени, чтобы изучить все эти дополнительные шаги и установку для простого задания соответствия текста.

Итак, Perl-камни для обработки текста и регулярного выражения.

У Python есть место для катания в других местах.

Обновить 29May2013: Отличная статья, которая делает аналогичное сравнение здесь. Perl снова выигрывает для простого сопоставления текста.. и для более подробной информации читайте статью.

  • 0
    Шаблоны компилируются только один раз в Python (как в Perl)?
  • 0
    Две программы эквивалентны? Я не вижу ничего похожего на / i в версии Python.
Показать ещё 16 комментариев
Теги:
performance
text-processing

6 ответов

17

Это именно тот материал, который был разработан Perl, поэтому меня не удивляет, что он быстрее.

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

exists_re = re.compile(r'^(.*?) INFO.*Such a record already exists')
location_re = re.compile(r'^AwbLocation (.*?) insert into')

И затем в вашем цикле:

mprev = exists_re.search(currline)

и

mcurr = location_re.search(currline)

Это само по себе не принесет волшебство вашему Python script в соответствии с вашим Perl script, но повторное вызов re в цикле без компиляции сначала - это плохая практика в Python.

  • 3
    re кеширует недавно использованные регулярные выражения, так что это, вероятно, не очень большая проблема.
  • 5
    @nneonneo Я слышал , что много раз , и я видел строки в re исходного кода , которые делают кэширование. Но почему-то я никогда не видел ни одного эталонного теста, который бы выставлял оба в одном и том же порядке, но несколько тестов (в том числе быстрый и грязный, который я сделал секунду назад), который позволял опцию предварительной компиляции в несколько раз быстрее.
Показать ещё 1 комментарий
12

Гипотеза: Perl тратит меньше времени на обратное отслеживание в строках, которые не совпадают из-за оптимизаций, которые у Python нет.

Что вы получаете, заменив

^(.*?) INFO.*Such a record already exists

с

^((?:(?! INFO).)*?) INFO.*Such a record already 

или

^(?>(.*?) INFO).*Such a record already exists
4

Вызов функций немного дороже с точки зрения времени на Python. И все же у вас есть вызов функции инварианта цикла, чтобы получить имя файла внутри цикла:

fn = fileinput.filename()

Переместите эту строку выше цикла for, и вы должны увидеть некоторое улучшение для вашего времени Python. Наверное, этого недостаточно, чтобы выбить Перла.

  • 1
    +1 для хорошего глаза, но ... Хорошо, но имя файла меняется. Это не инвариант цикла. В любом случае, может быть быстрее не использовать модуль fileinput и добавить еще один внешний цикл через имена файлов. Тогда имя файла будет инвариантом.
  • 1
    Интересный момент, но он должен быть крошечным по сравнению со временем обработки двух регулярных выражений.
3

@pepr Спасибо. Ваш код работает в течение 6,1 секунд (около 2 секунд улучшения) по сравнению с perl 1,8 секунды **

Но, мальчик, это чертовски сложно разобраться с этим код для среднего пользователя (меня).. кто, как правило, следует за быстрыми примерами от книги до фактического использования.

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

User@UserHP /cygdrive/d/tmp/Clipboard
# time /tmp/scripts/python/afs/process_file_pepr.py *log* *log* *log* *log* *lo
g* > summarypy_pepr.log

real    0m6.089s
user    0m5.772s
sys     0m0.155s
1

Я ожидаю, что Perl будет быстрее. Просто любопытно, можете ли вы попробовать следующее?

#!/usr/bin/python

import re
import glob
import sys
import os

exists_re = re.compile(r'^(.*?) INFO.*Such a record already exists', re.I)
location_re = re.compile(r'^AwbLocation (.*?) insert into', re.I)

for mask in sys.argv[1:]:
    for fname in glob.glob(mask):
        if os.path.isfile(fname):
            f = open(fname)
            for line in f:
                mex = exists_re.search(line)
                if mex:
                    xlogtime = mex.group(1)

                mloc = location_re.search(line)
                if mloc:
                    print fname, xlogtime, mloc.group(1)
            f.close()

Обновить в качестве реакции на "слишком сложно".

Конечно, он выглядит более сложным, чем версия Perl. Perl был построен вокруг регулярных выражений. Таким образом, вы вряд ли сможете найти интерпретируемый язык, который быстрее в регулярных выражениях. Синтаксис Perl...

while (<>) {
    ...
}

... также скрывает много вещей, которые нужно как-то делать на более общем языке. С другой стороны, довольно легко сделать код Python более удобным для чтения, если вы выведете нечитаемую часть:

#!/usr/bin/python

import re
import glob
import sys
import os

def input_files():
    '''The generator loops through the files defined by masks from cmd.'''
    for mask in sys.argv[1:]:
        for fname in glob.glob(mask):
            if os.path.isfile(fname):
                yield fname


exists_re = re.compile(r'^(.*?) INFO.*Such a record already exists', re.I)
location_re = re.compile(r'^AwbLocation (.*?) insert into', re.I)

for fname in input_files():
    with open(fname) as f:        # now the f.close() is done automatically
        for line in f:
            mex = exists_re.search(line)
            if mex:
                xlogtime = mex.group(1)

            mloc = location_re.search(line)
            if mloc:
                print fname, xlogtime, mloc.group(1)

Здесь def input_files() может быть помещен в другое место (например, в другом модуле), или он может быть повторно использован. Можно легко имитировать даже Perl while (<>) {...}, хотя и не так же синтаксически:

#!/usr/bin/python

import re
import glob
import sys
import os

def input_lines():
    '''The generator loops through the lines of the files defined by masks from cmd.'''
    for mask in sys.argv[1:]:
        for fname in glob.glob(mask):
            if os.path.isfile(fname):
                with open(fname) as f: # now the f.close() is done automatically
                    for line in f:
                        yield fname, line


exists_re = re.compile(r'^(.*?) INFO.*Such a record already exists', re.I)
location_re = re.compile(r'^AwbLocation (.*?) insert into', re.I)

for fname, line in input_lines():
    mex = exists_re.search(line)
    if mex:
        xlogtime = mex.group(1)

    mloc = location_re.search(line)
    if mloc:
        print fname, xlogtime, mloc.group(1)

Тогда последний for может выглядеть как простой (в принципе) как Perl while (<>) {...}. Такие улучшения чтения в Perl сложнее.

В любом случае, это не сделает программу Python быстрее. Теперь Perl будет быстрее. Perl является файловым/текстовым cruncher. Но, на мой взгляд, Python - лучший язык программирования для более общих целей.

  • 0
    @ihightower Пожалуйста, опубликуйте вашу попытку изменить как новый ответ.
  • 0
    извините сделаю. Благодарю.
Показать ещё 3 комментария
1

В целом, все искусственные тесты являются злыми.. Тем не менее, при прочих равных условиях (алгоритмический подход) вы можете делать улучшения на относительной основе. Однако следует отметить, что я не использую Perl, поэтому я не могу спорить в его пользу. При этом, используя Python, вы можете попробовать использовать Pyrex или Cython для повышения производительности. Или, если вы предприимчивы, вы можете попробовать преобразовать код Python в С++ с помощью ShedSkin (который работает для большей части основного языка и некоторые, но не все, из основных модулей).

Тем не менее, вы можете следить за приведенными здесь советами:

http://wiki.python.org/moin/PythonSpeed/PerformanceTips

  • 0
    я не являюсь экспертом по программированию на Perl или Python. Я использую Perl и Python таким образом, от того, что я читаю от обычного новичка до книги среднего уровня. Если мне нужна реальная производительность, я обязательно буду использовать ваши предложения и даже использовать ассемблер (если я когда-нибудь узнаю это). Использование того, что доступно в perl или python и его модулях, должно быть единственным предложением, которое я ожидаю улучшить код для повышения производительности. Я не собираюсь использовать другие магические умные слова и тратить время на изучение всего остального. Пожалуйста, предложите чистое решение, которое существует в установке nromal python.
  • 0
    Я понимаю, что все искусственные ориентиры могут быть злыми. Но обработка текста проста, и это то, что я обычно делаю изо дня в день. Итак, если Python не может улучшить скорость при использовании некоторого базового синтаксиса с в исходной установке Python ... (так же, как я делаю с Perl) ... Мне придется прибегнуть к Perl для моих задач обработки текста ... и для обработки 100 или 100 000 файлов, которые мне нужно обработать ... и нужно признать, что python медлен для простой обработки текста, как указано в моем коде. Но, боже, я хотел бы использовать python для его чистого синтаксиса, но с отставанием скорости ... не думаю, что так.
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню