我只是为 approved="no"
模式搜索一些 Xliff 文件。我有一个 Shell 脚本和一个 Python 脚本,性能差异很大(一组 393 个文件,总共 3,686,329 行,Shell 脚本的用户时间为 0.1s,Python 脚本的用户时间为 6.6s)。
外壳:grep 'approved="no"' FILE
python :
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
有任何使用多平台解决方案提高性能的想法吗?
结果
以下是应用一些建议的解决方案后的一些结果。
测试在装有 Python 2.6.6 的 RHEL6 Linux 机器上运行。
工作集:393个Xliff文件,共3,686,329行。
数字是以秒为单位的用户时间。
grep_1(io,加入 100,000 行文件):50 秒
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
并且您可以在知道结果后立即从函数返回。无需为每个单独的 ilne 运行 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()
The file was /usr/share/dict/words
containing approx 480,000 lines and the search pattern was zymurgies
, which occurs near the end of the file. For comparison, when pattern is near the start of the file, e.g. abaciscus
, the times are:
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()
which again shows that the mmap
version is fastest.
Now comparing the grep
command with the Python mmap
version:
$ 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
的优势,这还算不错。
关于Python grep 代码比命令行的 grep 慢得多,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38916645/