(Python)尽可能快地计算大型(>;10GB)文件中的行数
我现在有一个非常简单的脚本,它使用(Python)尽可能快地计算大型(>;10GB)文件中的行数,python,enumerate,line-count,Python,Enumerate,Line Count,我现在有一个非常简单的脚本,它使用enumerate()计算文本文件中的行数: 这需要大约3.5分钟来浏览一个15GB的日志文件,其中包含约3000万行。如果我能在两分钟或更短的时间内完成,那就太好了,因为这些是每日日志,我们希望每月进行一次分析,因此代码必须处理30个~15GB的日志-可能超过一个半小时,我们希望将服务器上的时间和内存负载降至最低 我也会满足于一个很好的近似/估计方法,但它需要大约4sig的精确度 谢谢大家! 读取文件,并计算换行符。是正确的,但如果使用32位进程,则可能会失败
enumerate()
计算文本文件中的行数:
这需要大约3.5分钟来浏览一个15GB的日志文件,其中包含约3000万行。如果我能在两分钟或更短的时间内完成,那就太好了,因为这些是每日日志,我们希望每月进行一次分析,因此代码必须处理30个~15GB的日志-可能超过一个半小时,我们希望将服务器上的时间和内存负载降至最低
我也会满足于一个很好的近似/估计方法,但它需要大约4sig的精确度
谢谢大家! 读取文件,并计算换行符。是正确的,但如果使用32位进程,则可能会失败
但是,按块读取文件,然后计算每个块中的\n
字符可能会有用
def blocks(files, size=65536):
while True:
b = files.read(size)
if not b: break
yield b
with open("file", "r") as f:
print sum(bl.count("\n") for bl in blocks(f))
我会做好你的工作
请注意,我没有以二进制方式打开文件,因此\r\n
将转换为\n
,从而使计数更加可靠
对于Python 3,为了使其更健壮,可以读取包含各种字符的文件:
def blocks(files, size=65536):
while True:
b = files.read(size)
if not b: break
yield b
with open("file", "r",encoding="utf-8",errors='ignore') as f:
print (sum(bl.count("\n") for bl in blocks(f)))
我知道这有点不公平,但你可以这么做
int(subprocess.check_output("wc -l C:\\alarm.bat").split()[0])
如果您使用的是Windows,请查看。一个快速的单线解决方案是:
sum(1 for i in open(file_path, 'rb'))
它可以处理任意大小的文件。我会扩展gl的答案,并使用多处理Python模块运行他/她的代码,以加快计数:
def blocks(f, cut, size=64*1024): # 65536
start, chunk =cut
iter=0
read_size=int(size)
_break =False
while not _break:
if _break: break
if f.tell()+size>start+chunk:
read_size=int(start+chunk- f.tell() )
_break=True
b = f.read(read_size)
iter +=1
if not b: break
yield b
def get_chunk_line_count(data):
fn, chunk_id, cut = data
start, chunk =cut
cnt =0
last_bl=None
with open(fn, "r") as f:
if 0:
f.seek(start)
bl = f.read(chunk)
cnt= bl.count('\n')
else:
f.seek(start)
for i, bl in enumerate(blocks(f,cut)):
cnt += bl.count('\n')
last_bl=bl
if not last_bl.endswith('\n'):
cnt -=1
return cnt
....
pool = multiprocessing.Pool(processes=pool_size,
initializer=start_process,
)
pool_outputs = pool.map(get_chunk_line_count, inputs)
pool.close() # no more tasks
pool.join()
这将使计数性能提高20倍。
我将其包装到a并将其放入Github。一般来说,将文件作为二进制数据处理,以合理大小的块(例如,每次4KB)读取,并在运行时计算每个块中的
\n
字符可能会更快。这并没有比您的原始解决方案更好的性能,但是,仅供参考,用python的方式来编写您在这里的内容只需使用open(fname)作为f:print sum(f中的行为1)aroth:谢谢你的提示,我应该研究一下。维姆:太好了,谢谢,这要短得多……看看迈克尔·培根的答案。这可能对你有帮助!我的解决方案只需要1m37实时。这是非常快的,就像你需要对python3执行int(subprocess.check\u输出(“/usr/bin/wc-l cred”,shell=True)。split()[0])
,如果你有大文件或很多文件,请考虑使用这种方法,如果你正在寻找纯粹的性能而不诉诸另一种语言。作为一个数据点,一个大约51 MB的大文件的读取从大约一分钟使用天真的方法使用这个方法下一秒。@ MkATZ现在,“一个大文件”或“大约51 MB的文件”?此解决方案可能会漏掉最后一行,但对于大型文件来说,这可能并不重要。@ngọ仅当最后一行不完整时才使用cminh.oss。文本文件定义为以换行符结尾,请参见和。人们并不关心定义。处理真实数据时,一切都很混乱。但是这没关系。请考虑添加一个简短的例子来证明这一点,谢谢!简短的例子可能是个好主意,我同意我确认这是最快的一个(除了wc-l
hack)。使用文本模式在性能上会有一点下降,但与其他解决方案相比,这是微不足道的。顺便说一句,有一个不需要的额外生成器括号。如果没有不需要的额外生成器括号,它似乎要快得多(每timeit),并消耗大约3MB内存(对于100000行的文件,每个memit)…如果文件是带有换行符的文本文件,则似乎不起作用。我的问题是需要字符计数的大型txt文件。@olekb感谢您分享多处理方法。作为一个新手,我们如何运行这段代码来计算一个大文件中的一行(比如说,'myfile.txt')?我是否尝试了pool=multiprocessing.pool(4);pool\u outputs=pool.map(获取\u chunk\u line\u count,'myfile.txt')
,但这会导致错误。提前感谢您的回答!
def blocks(f, cut, size=64*1024): # 65536
start, chunk =cut
iter=0
read_size=int(size)
_break =False
while not _break:
if _break: break
if f.tell()+size>start+chunk:
read_size=int(start+chunk- f.tell() )
_break=True
b = f.read(read_size)
iter +=1
if not b: break
yield b
def get_chunk_line_count(data):
fn, chunk_id, cut = data
start, chunk =cut
cnt =0
last_bl=None
with open(fn, "r") as f:
if 0:
f.seek(start)
bl = f.read(chunk)
cnt= bl.count('\n')
else:
f.seek(start)
for i, bl in enumerate(blocks(f,cut)):
cnt += bl.count('\n')
last_bl=bl
if not last_bl.endswith('\n'):
cnt -=1
return cnt
....
pool = multiprocessing.Pool(processes=pool_size,
initializer=start_process,
)
pool_outputs = pool.map(get_chunk_line_count, inputs)
pool.close() # no more tasks
pool.join()