(Python)尽可能快地计算一个巨大(> 10GB)文件中的行数[重复]
Posted
技术标签:
【中文标题】(Python)尽可能快地计算一个巨大(> 10GB)文件中的行数[重复]【英文标题】:(Python) Counting lines in a huge (>10GB) file as fast as possible [duplicate] 【发布时间】:2012-03-26 14:47:01 【问题描述】:我现在有一个非常简单的脚本,它使用 enumerate()
计算文本文件中的行数:
i = 0
f = open("C:/Users/guest/Desktop/file.log", "r")
for i, line in enumerate(f):
pass
print i + 1
f.close()
浏览一个 15GB 的日志文件大约需要 3 分半钟,其中包含约 3000 万行。如果我能在两分钟或更短的时间内完成它会很棒,因为这些是每日日志,我们希望每月进行一次分析,所以代码将不得不处理 30 个约 15GB 的日志 - 可能超过一个半小时,并且我们希望最大限度地减少服务器上的时间和内存负载。
我也会满足于一个好的近似/估计方法,但它需要大约 4 sig fig 准确...
谢谢!
【问题讨论】:
一般来说,将文件视为二进制数据,以合理大小的块(例如,一次 4KB)读取文件并计算每个块中的\n
字符可能会更快随你去。
这并不比你幼稚的解决方案表现更好,但供你参考的pythonic方式来写你在这里所拥有的只是with open(fname) as f: print sum(1 for line in f)
aroth:感谢您的提示,我应该调查一下。 wim:太好了,谢谢,这要短得多...
看看rawbigcount Michael Bacon 的回答。可能对你有帮助!
【参考方案1】:
Ignacio's answer 是正确的,但如果您使用 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)))
【讨论】:
就像一个数据点一样,读取大约 51 MB 的大文件从使用简单方法的大约一分钟到使用这种方法的不到一秒。 @MKatz 现在是“一个大文件”还是“一个大约 51 MB 的文件”? ;-) 此解决方案可能会遗漏最后一行,但这对于大文件可能无关紧要。 @ngọcminh.oss 仅当最后一行不完整时。文本文件定义为以换行符结尾,请参阅pubs.opengroup.org/onlinepubs/9699919799/basedefs/… 和***.com/a/729795/296974。 并不是人们关心定义。当您使用真实数据时,一切都很混乱。不过没关系。【参考方案2】:我知道这有点不公平,但你可以这样做
int(subprocess.check_output("wc -l C:\\alarm.bat").split()[0])
如果您使用的是 Windows,请查看Coreutils。
【讨论】:
我的解决方案只需要 1m37 实时。 这要快得多 看来你需要为python3做int(subprocess.check_output("/usr/bin/wc -l cred", shell=True).split()[0])
如果您有大文件或很多文件,如果您正在寻找纯粹的性能而不求助于其他语言,请考虑使用这种方法。【参考方案3】:
一种快速的单行解决方案是:
sum(1 for i in open(file_path, 'rb'))
它应该适用于任意大小的文件。
【讨论】:
我确认这是最快的(wc -l
hack 除外)。使用文本模式在性能上会有所下降,但与其他解决方案相比是微不足道的。
有一个不需要的额外生成器括号,顺便说一句。
如果没有多余的生成器括号,它似乎会稍微快一些(每 timeit)并且消耗大约 3MB 的内存(对于 100,000 行的文件,每 memit)..
如果文件是带有换行符的文本文件,似乎不起作用。我的问题是需要字符计数的大 txt 文件。
文件没有关闭。【参考方案4】:
mmap 文件,并计算换行符。
【讨论】:
请考虑添加一个简短的示例来演示这一点,谢谢! 简短的例子可能是个好主意,我同意【参考方案5】:我会扩展 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 倍。 我把它打包到 script 并放到 Github 上。
【讨论】:
@olekb 感谢您分享多处理方法。作为新手的快速问题,我们如何运行这段代码来计算大文件中的一行(比如,'myfile.txt')?我是否尝试过pool = multiprocessing.Pool(4); pool_outputs = pool.map(get_chunk_line_count, 'myfile.txt')
,但这会导致错误。提前感谢您的回答!以上是关于(Python)尽可能快地计算一个巨大(> 10GB)文件中的行数[重复]的主要内容,如果未能解决你的问题,请参考以下文章
Windows科学计算器与Python,计算结果的巨大差异?
我想强制渲染,但尽可能快地绘制(InvalidateVisual / CompositionTarget.Rendering)