簡體   English   中英

Python grep代碼比命令行的grep慢得多

[英]Python grep code much slower than command line's grep

我只是為了模式approved="no"來一些Xliff文件。 我有一個Shell腳本和一個Python腳本,性能差異很大(對於一組393個文件,總共3,686,329行,Shell腳本的用戶時間為0.1s,Python腳本為6.6s)。

Shell: grep 'approved="no"' FILE
蟒蛇:

def grep(pattern, file_path):
    ret = False

    with codecs.open(file_path, "r", encoding="utf-8") as f:
        while 1 and not ret:
            lines = f.readlines(100000)
            if not lines:
                break
            for line in lines:
                if re.search(pattern, line):
                    ret = True
                    break
    return ret

有關使用多平台解決方案提高性能的任何想法嗎?

結果

在應用一些建議的解決方案后,這里有幾個結果。
測試在RHEL6 Linux機器上運行,使用Python 2.6.6。
工作集:393個Xliff文件,總計3,686,329行。
數字是用戶時間,以秒為單位。

grep_1 (io,加入100,000個文件行):50s
grep_3 (mmap): 0.7s
Shell版本 (Linux grep):0.130s

Python,作為解釋語言與grep的編譯C版本將總是較慢。

除此之外,你的Python實現是一樣的你grep例子。 它沒有返回匹配的行,它只是測試模式是否匹配任何一行上的字符。 更接近的比較是:

grep -q 'approved="no"' FILE

一旦找到匹配就會返回,並且不會產生任何輸出。

通過更有效地編寫grep()函數,可以大大加快代碼速度:

def grep_1(pattern, file_path):
    with io.open(file_path, "r", encoding="utf-8") as f:
        while True:
            lines = f.readlines(100000)
            if not lines:
                return False
            if re.search(pattern, ''.join(lines)):
                return True

這使用io而不是我發現的codecs更快一點。 while循環條件不需要檢查ret ,一旦結果已知,就可以從函數返回。 沒有必要為每個單獨的元素運行re.search() - 只需加入行並執行單個搜索。

以內存使用為代價,您可以嘗試這樣做:

import io

def grep_2(pattern, file_path):
    with io.open(file_path, "r", encoding="utf-8") as f:
        return re.search(pattern, f.read())

如果內存是個問題,你可以mmap文件並在mmap上運行正則表達式搜索:

import io
import mmap

def grep_3(pattern, file_path):
    with io.open(file_path, "r", encoding="utf-8") as f:
        return re.search(pattern, mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ))

mmap將有效地從頁面中的文件中讀取數據,而不會占用大量內存。 此外,您可能會發現mmap比其他解決方案運行得更快。


對每個函數使用timeit表明情況如此:

10 loops, best of 3: 639 msec per loop       # grep()
10 loops, best of 3: 78.7 msec per loop      # grep_1()
10 loops, best of 3: 19.4 msec per loop      # grep_2()
100 loops, best of 3: 5.32 msec per loop     # grep_3()

文件是/usr/share/dict/words包含大約480,000行的/usr/share/dict/words ,搜索模式是zymurgies ,它出現在文件末尾附近。 為了比較,當模式接近文件的開頭時,例如abaciscus ,時間是:

10 loops, best of 3: 62.6 msec per loop       # grep()
1000 loops, best of 3: 1.6 msec per loop      # grep_1()
100 loops, best of 3: 14.2 msec per loop      # grep_2()
10000 loops, best of 3: 37.2 usec per loop    # grep_3()

這再次表明mmap版本最快。


現在將grep命令與Python mmap版本進行比較:

$ time grep -q zymurgies /usr/share/dict/words

real    0m0.010s
user    0m0.007s
sys 0m0.003s

$ time python x.py grep_3    # uses mmap

real    0m0.023s
user    0m0.019s
sys 0m0.004s

考慮到grep的優勢,這並不算太糟糕。

Grep實際上是一個非常聰明的軟件,它不僅僅是每行進行正則表達式搜索。 它利用了Boyer-Moore算法。 有關更多信息,請參見此處

有關更多指針,請參閱此處獲取grep的python實現。

這里緩慢的另一個原因是在循環中調用re.search 這將重新編譯每一行的正則表達式。

嘗試改為:

pattern = re.compile(pattern)
while True:
    ...
    if pattern.search(line):
    ...

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM