Python 最快的方式;grep“;大文件
我有很大的日志文件(从100MB到2GB),其中包含一行(单个)我需要在Python程序中解析的特定行。我必须解析大约20000个文件。我知道搜索的行在文件的最后200行内,或者在最后15000字节内 由于这是一项经常性的任务,我需要它尽可能快。最快的方式是什么 我考虑了4种策略:Python 最快的方式;grep“;大文件,python,python-2.7,Python,Python 2.7,我有很大的日志文件(从100MB到2GB),其中包含一行(单个)我需要在Python程序中解析的特定行。我必须解析大约20000个文件。我知道搜索的行在文件的最后200行内,或者在最后15000字节内 由于这是一项经常性的任务,我需要它尽可能快。最快的方式是什么 我考虑了4种策略: 用Python读取整个文件并搜索正则表达式(方法_1) 仅读取文件的最后15000字节并搜索正则表达式(方法2) 对grep进行系统调用(方法3) 在跟踪最后200行后对grep进行系统调用(方法4) 以下是我为
- 用Python读取整个文件并搜索正则表达式(方法_1)
- 仅读取文件的最后15000字节并搜索正则表达式(方法2)
- 对grep进行系统调用(方法3)
- 在跟踪最后200行后对grep进行系统调用(方法4)
import os
import re
import subprocess
def method_1(filename):
"""Method 1: read whole file and regex"""
regex = r'\(TEMPS CP :[ ]*.*S\)'
with open(filename, 'r') as f:
txt = f.read()
match = re.search(regex, txt)
if match:
print match.group()
def method_2(filename):
"""Method 2: read part of the file and regex"""
regex = r'\(TEMPS CP :[ ]*.*S\)'
with open(filename, 'r') as f:
size = min(15000, os.stat(filename).st_size)
f.seek(-size, os.SEEK_END)
txt = f.read(size)
match = re.search(regex, txt)
if match:
print match.group()
def method_3(filename):
"""Method 3: grep the entire file"""
cmd = 'grep "(TEMPS CP :" {} | head -n 1'.format(filename)
process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
print process.communicate()[0][:-1]
def method_4(filename):
"""Method 4: tail of the file and grep"""
cmd = 'tail -n 200 {} | grep "(TEMPS CP :"'.format(filename)
process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
print process.communicate()[0][:-1]
我在两个文件上运行了这些方法(“trace”是207MB,“trace_big”是1.9GB),得到了以下计算时间(以秒为单位):
所以方法2似乎是最快的。但是有没有其他我没有想到的解决办法呢
编辑
除了前面的方法外,Gosha F建议使用mmap的第五种方法:
import contextlib
import math
import mmap
def method_5(filename):
"""Method 5: use memory mapping and regex"""
regex = re.compile(r'\(TEMPS CP :[ ]*.*S\)')
offset = max(0, os.stat(filename).st_size - 15000)
ag = mmap.ALLOCATIONGRANULARITY
offset = ag * (int(math.ceil(offset/ag)))
with open(filename, 'r') as f:
mm = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_COPY, offset=offset)
with contextlib.closing(mm) as txt:
match = regex.search(txt)
if match:
print match.group()
我对它进行了测试,得到了以下结果:
+----------+-----------+-----------+
| | trace | trace_big |
+----------+-----------+-----------+
| method_5 | 2.50E-004 | 2.71E-004 |
+----------+-----------+-----------+
在shell中进行处理可能会更快,以避免python开销。然后,您可以将结果通过管道传输到python脚本中。否则看起来你做得最快
然后寻找正则表达式匹配应该是非常快的。方法2和方法4是相同的,但会导致python进行系统调用的额外开销。它必须是python吗?为什么不是shell脚本?
我猜方法4将是最快/最有效的。这当然是我作为shell脚本编写它的方式。它的速度比1或3快。与方法2相比,我仍然可以用它来确定100%。 ,您也可以考虑使用内存映射(模块),如。
def method_5(filename):
"""Method 5: use memory mapping and regex"""
regex = re.compile(r'\(TEMPS CP :[ ]*.*S\)')
offset = max(0, os.stat(filename).st_size - 15000)
with open(filename, 'r') as f:
with contextlib.closing(mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_COPY, offset=offset)) as txt:
match = regex.search(txt)
if match:
print match.group()
还有一些旁注:
- 在使用shell命令的情况下,在某些情况下可能比grep快几个数量级(尽管只有200行greppable文本,与启动shell的开销相比,差异可能会消失)
- 只需在函数开头编译正则表达式可能会有所不同
mmap.mmap
中,偏移量必须是mmap.ALLOCATIONGRANULARITY的倍数,因此我在其最接近的上限倍数上加了一个整数。
def method_5(filename):
"""Method 5: use memory mapping and regex"""
regex = re.compile(r'\(TEMPS CP :[ ]*.*S\)')
offset = max(0, os.stat(filename).st_size - 15000)
with open(filename, 'r') as f:
with contextlib.closing(mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_COPY, offset=offset)) as txt:
match = regex.search(txt)
if match:
print match.group()