【问题标题】:Fastest way to read file searching for pattern matches读取文件搜索模式匹配的最快方法
【发布时间】:2016-07-01 20:29:00
【问题描述】:

我制作了一个 python 脚本来分析日志。我有一个观察要分享,还有两个问题要问。

当我使用 gzip.open 打开每个文件并浏览每一行时,浏览所有行和文件大约需要 200 秒。

with gzip.open(file) as fp:
    for line in fp:
          pass

如果使用zcatgrep 来完成这项工作,大约需要 50 秒。

temp = commands.getstatusoutput("zcat file* | grep pattern")

性能差异太大,不容忽视。有没有更好的方法来缩小差距?

我还注意到commands 模块已被subprocess 模块淘汰,这似乎总是创建一个临时文件。但这不方便,如果无法从运行 python 脚本的位置创建临时文件怎么办?有什么建议吗?

【问题讨论】:

  • 我怀疑差异仅在于迭代。你对循环中的每一行做了什么?
  • 请记住,grep 使用了一些极其完善的代码生成技术来优化其速度。它可能很旧,但这并不意味着它很糟糕——在这种情况下,恰恰相反。你可能会花费数十年的时间来尝试跟上它的速度,但不能接近,因为制造它的人非常非常聪明。 (例如,见lists.freebsd.org/pipermail/freebsd-current/2010-August/…
  • 如果上面显示的 Python 'for' 循环确实是空的,并且速度差异是由于 zcat 和 Python 的 gzip 之间的差异造成的:您可以尝试一个实验。如果您手动解压缩文件,然后将 Python 的 'gzip.open' 替换为常规的 'open',会发生什么情况。这可能会揭示导致放缓的原因。
  • 我已经修改了我的帖子。我最初试图找到一些模式。后来,为了进行基准测试,我戴上了“通过”来衡量时间。
  • @Jonathan Hartley 我喜欢你关于消除 gzip.open 和 zcat 影响的建议。我解压缩了 .log.gz 文件并比较了速度。结果是使用python遍历每一行需要36秒,而使用grep需要6.5秒。

标签: python grep


【解决方案1】:

'grep' 包含十年来的优化,并且在任何编程语言中重新实现它,而不仅仅是 Python,都会更慢。 *1

因此,如果速度对您很重要,那么您直接调用“grep”的技术可能是可行的方法。要使用 'subprocess' 执行此操作,无需编写任何临时文件,请使用 'subprocess.PIPE' 机制:

from subprocess import Popen, PIPE

COMMAND = 'zcat file* | grep oldconfig'
process = Popen(COMMAND, shell=True, stderr=PIPE, stdout=PIPE)
output, errors = process.communicate()
assert process.returncode == 0, process.returncode
assert errors == '', errors
print('{} lines match'.format(len(output.splitlines())))

这适用于我在 Python3.5 上。我最近避免使用在子进程之上添加的任何更高级别的接口,因此它也应该可以在旧版本的 Python 上正常工作。


(*1 例如,即使使用空的“for”循环,正如您在问题中所示,grep 可能仍然更快,因为它不会逐行读取输入。而是确定它可以通过文件向前搜索的最大字符数,完全忽略换行符,每次搜索后读取一个字符,搜索可能匹配正则表达式任何部分的字符。只有找到匹配项,它才会查看该字符周围的字符match, 以查看其余的正则表达式是否匹配以及是否存在适当的换行符。最重要的是,它动态生成硬编码的代码以检查与给定正则表达式的匹配,这意味着它每个输入字节执行大约 3 个 x86 指令它会检查,并完全跳过检查大多数输入字节)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-05-02
    • 2017-12-31
    • 2022-01-13
    • 2012-08-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多