[英]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.