2013-11-27 3 views
1

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

for $line in (<FILE>) { 
    ($stuff1, $stuff2, $etc) = split(/\s+/, $line); 
    $stuff1 =~ s/something//; 
    $stuff2 =~ s/something//; 
    $count1{$stuff1}++; 
    $count2{$stuff2}++; 
} 
etc, print the hashes 

Мой Python выглядит следующим образом:

import re 
from collections import defaultdict 

cntdaemon = defaultdict(int) 
cntfaclevel = defaultdict(int) 
cnthost = defaultdict(int) 
redaemon1 = re.compile('\[[0-9]+\]') 
redaemon2= re.compile(':') 
refaclevel= re.compile(']') 
with open("/var/adm/messages", 'r') as infile: 
    for line in infile: 
     (m, d, t, host, daemon, junk, idno, faclevel, text) = line.split(' ',8) 
     daemon = re.sub(redaemon1, '', daemon) 
     daemon = re.sub(redaemon2, '', daemon) 
     cntdaemon[daemon] += 1 
     faclevel = re.sub(refaclevel, '', faclevel) 
     cntfaclevel[faclevel] += 1 
     cnthost[host] += 1 
print cntdaemon 
print cntfaclevel 
print cnthost 

Я нахожу, что это работает примерно в 20 раз медленнее, чем версия Perl. Я запускал тестовые файлы, предварительно компилируя регулярные выражения и компилируя их «на лету», и существует незначительная разница, поэтому я знаю, что Python не тратит время на компиляцию регулярных выражений. Мое подозрение в том, что он тратит все свое время на уничтожение и компиляцию строк каждый раз, когда я делаю «re.sub».

Итак, простой вопрос - есть ли идиома, чтобы сделать замену быстрее?

Я думаю, я всегда мог попробовать написать функцию, чтобы сделать это без назначения .... это то, что часто используется подход? Можно преобразовать строку в список, а затем через нее, стиль строки C/C++ (ну, я просто выбрасываю это там ...)

Это может быть важно (и именно поэтому я не используйте Counter() в примере). Мне нужно написать это в Python 2.6.4. Если бы это было намного быстрее в 2.7 или 3, просто скажите это. Но у меня нет выбора.

+3

1 символьные регулярные выражения могут быть ускорены с помощью 'str.replace' или' str.translate (None, ':') ' – mgilson

+1

Действительно, пропуская ненужные вызовы' re.sub', нужно ускорить скрипт примерно в три раза , не говоря уже о преимуществах чтения. Но лично я бы сделал это в Awk, а не на Python, если бы это было быстро. –

+0

Интересно - я обрезал syslog fie назад, я читал назад примерно с 4 000 000 строк до 20 000 строк, а версия Python работает примерно столько же времени, сколько и версия Perl. Итак: – wsanders

ответ

1

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

Начните комментировать строки, которые не имеют других вычислений в зависимости от них.

line = "blah blah..."  # typical line from the file 
for i in range(10000): # pretend there are 10000 lines 
    (m, d, t, host, daemon, junk, idno, faclevel, text) = line.split(' ',8) 
    daemon = re.sub(redaemon1, '', daemon) 
    daemon = re.sub(redaemon2, '', daemon) 
    cntdaemon[daemon] += 1 
    faclevel = re.sub(refaclevel, '', faclevel) 
    cntfaclevel[faclevel] += 1 
# cnthost[host] += 1 

Теперь вы можете работать, сколько времени занимает cnthost[host] += 1

line = "blah blah..."  # typical line from the file 
for i in range(10000): # pretend there are 10000 lines 
    (m, d, t, host, daemon, junk, idno, faclevel, text) = line.split(' ',8) 
    daemon = re.sub(redaemon1, '', daemon) 
    daemon = re.sub(redaemon2, '', daemon) 
    cntdaemon[daemon] += 1 
    faclevel = re.sub(refaclevel, '', faclevel) 
# cntfaclevel[faclevel] += 1 
# cnthost[host] += 1  # takes 20 seconds 

Теперь вы можете работать, сколько времени занимает cntfaclevel[faclevel] += 1

и т.д.

После того, как вы отработали hotspot - тогда начните думать о способах сделать это быстрее.

Если вы можете добавить типичную строку, которую вы обрабатываете на вопрос, мы сможем увидеть, есть ли какие-либо трюки, которые могут быть использованы, или если вы что-то особенное делаете плохо.

+0

Ну, комментируя хэш [key] = + 1 строки, многое не изменилось. Комментируя функции «re» по одному, время от времени пропорционально количеству повторных операций. Так что re определенно является узким местом, будь то re.sub() или re.split(). Я обрезал syslog, который я читал с примерно 4 000 000 строк до 20 000 строк, а версия Python работает примерно столько же времени, что и версия Perl в этих сценариях. Я снова сделаю еще несколько проверок на следующей неделе. Str.replace и str.перевод предложений был полезным, и мне просто напомнили о ключевом слове «in». – wsanders

+0

@wsanders, я не могу помочь вам оптимизировать его больше, не видя, как выглядят линии. –

Смежные вопросы