繁体   English   中英

itertools.islice和read函数之间的区别

[英]Difference between itertools.islice and read function

我试图更好地了解如何以最小的内存使用量处理具有数百万条记录的文件。

为了练习,我创建了一个约650万行的文件,并编写了一些函数将其拆分为约7个文件,每行有100万行。 在第一个函数中,我使用了python文件读取方法来创建逻辑,以便在读取100万行之后创建一个新文件,直到找到最后写入500K行的最后一个文件为止。

该功能需要永远运行。

然后,我创建了另一个函数,使用itertools.islice拆分文件。 运行大约不到2秒的时间。

现在,我知道islice是一个迭代文件对象的迭代器,因此它有望提高内存效率。 但是,它与read()方法有何不同?

我以为read()甚至遍历文件中的每一行(有点像迭代器..)。 因此,我期望两个程序的性能相似。 你们可以帮助我理解为什么islice这么快吗?

这都是两段代码-

1使用read()-

with open("bigfile.txt","r") as f:
    filenum = 1
    j = 1
    for i, line in enumerate(f):
        if j <= 1000000:
            with open("big_out_%d" % filenum, "a") as outfile:
                outfile.write(line)
        j += 1
        if j == 1000000:
            j = 1
            filenum += 1
            with open("big_out_%d" % filenum, "a") as outfile:
                outfile.write(line)

2使用islice-

import itertools
import time

start = time.time()

with open("bigfile.txt","r") as f:
    i = 1
    while True:
        chunk = list(itertools.islice(f, 1000000))
        if not chunk:
            print "reached the end"
            break
        with open("out%d.txt" % i, "w") as out:
            out.writelines(chunk)
        print i
        i += 1

end = time.time()
print "time is %d" % ((end-start))

区别与islice和read()没有关系。 您的两个程序的逻辑差异很大。

在第一个清单中,您遍历文件的各行。 在循环的每次迭代中,您都将打开文件,写一行,然后再次关闭文件。 (“ with open”语法使文件在with:块的末尾关闭)。 在完成时,您已经将6500000行写入了七个不同的文件,但是您还执行了6500000文件打开和6500000文件关闭的操作。 操作系统不能有效地做到这一点,我并不感到惊讶。

在第二个清单中,您读入了1000000行的块,然后将所有这些写一次。 您仍然编写6500000行,但是在这里执行7次打开和7次关闭。 完全不一样。

对输出文件使用with:使您的第一个清单非常笨拙。 尝试这个:

with open("bigfile.txt","r") as f:
    filenum = 1
    j = 1
    outfile = open("big_out_%d" % filenum, "w")
    try:
        for line in f:
            outfile.write(line)
            j += 1
            if j == 1000000:
                outfile.close()
                j = 1
                filenum += 1
                outfile = open("big_out_%d" % filenum, "w")
    finally:
        outfile.close()

我没有测试此代码。 如果有错误,应该很容易解决。

使用这种方法,您一次加载到内存中永远不会超过一行。

该代码的第一个版本打开并关闭它写入的每一行的输出文件。 这将非常慢,因为它将每次将缓冲区刷新到磁盘。 仅保持文件在两行之间打开可能是第二个版本的最大提速(尽管连续读取和写入许多行可能会带来适度的额外好处,只要您可以同时将所有行保存在内存中即可)。

您可以尝试使用该代码的第三个版本,这是当前两个版本之间的一部分。 它仍然读取和写入单行,但是在两次写入之间保持输出文件打开:

with open("bigfile.txt","r") as f:
    outfile = None
    for i, line in enumerate(f):
        if i % 1000000 == 0:
            if outfile:
                outfile.close()
            outfile = open("big_out_%d" % (i // 1000000), "w")
        outfile.write(line)
    if outfile:
        outfile.close()

请注意,通过对所有计数使用enumerate索引i来简化事情,而不是在第一个代码中手动更新filenumj整数。 这不太可能对性能产生重大影响,但是会使代码更好。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM