2013-11-27 96 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 

我發現這個版本比Perl版本慢20倍左右。我已經運行了預編譯正則表達式的測試用例,並對其進行了「即時編譯」,並且可以忽略不計,所以我知道Python不會浪費時間編譯正則表達式。我懷疑是每次我做一個「re.sub」的時候,它會花費我所有的時間來銷燬和編譯字符串。

所以,簡單的問題 - 有一個成語做替代更快?

我想我總是可以嘗試寫一個函數來做到這一點,而不分配....是一種方法往往採取?人們可以通過它的字符串轉換成一個列表,然後ITER,C/C++字符串風格(當然,我只是那個扔在那裏...)

這可能是重要的(也就是爲什麼我不在示例中使用Counter()) - 我需要在Python 2.6.4中編寫它。如果這在2.7或3中會快得多,就這麼說吧。但我沒有選擇。

+3

1個字符的正則表達式可以通過'str.replace'或'str.translate(None,':')''加快速度。 – mgilson

+1

實際上,跳過不必要的're.sub'調用應該可以使腳本速度提高三倍,更不用說可讀性的好處了。但個人而言,如果它必須快速,我會在Awk中做這種事情,而不是Python。 –

+0

有趣 - 我修剪系統日誌外商投資企業後,我是從約4,000,000行讀回至20000線和Py​​thon版本在大約相同的時間量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多少時間

一旦你制定出熱點 - 然後開始思考如何使其更快。

如果您可以添加一個典型的字符串,您正在處理的問題,我們將能夠看到是否有特定的技巧可以使用,或者如果有什麼特別的性能明智的表現。

+0

好吧,註釋掉hash [key] = + 1行並沒有太大的改變。逐一評論「重新」功能需要花費時間與註釋的重新操作次數成比例。所以無論是re.sub()還是re.split(),re肯定是一個瓶頸。 我修整了從大約400萬行讀到20000行的系統日誌,Python版本的運行時間與那些場景中的Perl版本大致相同。我會在下週再做一次檢查。 str.replace和str。翻譯建議是有幫助的,我只是想起了「in」關鍵字。 – wsanders

+0

@wsanders,我不能幫助你更好地優化它,而不會看到線條的樣子。 –