关于enumerate:(Python)尽可能快地计算巨大(> 10GB)文件中的行

(Python) Counting lines in a huge (>10GB) file as fast as possible

本问题已经有最佳答案,请猛点这里访问。

我现在有一个非常简单的脚本,它使用enumerate()计算文本文件中的行数:

1
2
3
4
5
6
i = 0
f = open("C:/Users/guest/Desktop/file.log","r")
for i, line in enumerate(f):
      pass
print i + 1
f.close()

这需要大约3.5分钟的时间来完成一个15GB的日志文件,其中包含大约3000万行。如果我能在两分钟或更短的时间内完成这项工作,那就太好了,因为这些是日常日志,我们希望每月进行一次分析,因此代码必须处理30个大约15GB的日志,可能超过一个半小时,我们希望将服务器上的时间和内存负载降到最低。

我也会解决一个好的近似/估计方法,但它需要大约4西格图准确…

谢谢您!


伊格纳西奥的回答是的先生也可能会失败,但如果你有一个32位的过程。 P / < >

但也许它可以useful读到的文件块明智的,然后在每一块的
count个字符。 P / < >

1
2
3
4
5
6
7
8
9
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("
"
) for bl in blocks(f))

会做你的工作。 P / < >

注意,我不要打开的文件为二进制,这样的

将converted到
,制作更多的reliable的计数。 P / < >

为Python 3,和使它更强大,为阅读的文件与所有kinds的字符数: P / < >

1
2
3
4
5
6
7
8
9
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("
"
) for bl in blocks(f)))


我知道它的不公平,但你能做到这一点 P / < >

1
int(subprocess.check_output("wc -l C:\\alarm.bat").split()[0])

如果你是在Windows,看看coreutils。 P / < >


一个快速,1在线解决方案: P / < >

1
sum(1 for i in open(file_path, 'rb'))

它应该工作文件的arbitrary尺寸。 P / < >


mmap同步的文件,和计数的newlines起来。 P / < >


I’d extend GL的答案和跑他/她使用的代码multiprocessing Python模块为更快的count: P / < >

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
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('
'
)
        else:
            f.seek(start)
            for i, bl  in enumerate(blocks(f,cut)):
                cnt +=  bl.count('
'
)
                last_bl=bl

        if not last_bl.endswith('
'
):
            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()

这将improve列入20 folds性能。 我wrapped它到脚本和把它放到github。 P / < >