一尘不染

处理大文件的最快方法?

python

我有多个3 GB的制表符分隔文件。每个文件中有2000万行。所有行都必须独立处理,任何两行之间都没有关系。我的问题是,什么会更快A.使用以下命令逐行阅读:

with open() as infile:
    for line in infile:

还是B.将文件分块读取到内存中并进行处理,例如一次250 MB?

处理不是很复杂,我只是在column1到List1column2的值中抓取值,List2等等。可能需要将一些列值加在一起。

我在具有30GB内存的Linux机器上使用python 2.7。ASCII文本。

有什么办法可以并行加速吗?现在,我正在使用前一种方法,该过程非常缓慢。使用任何CSVReader模块都会有所帮助吗?我不必用python来做,欢迎任何其他语言或数据库使用的想法。


阅读 123

收藏
2020-12-20

共1个答案

一尘不染

听起来您的代码受I / O约束。这意味着多处理将无济于事-如果您花费90%的时间从磁盘读取数据,那么等待下一次读取的额外7个进程将无济于事。

而且,尽管使用CSV读取模块(无论是stdlibcsv还是NumPy或Pandas之类的东西)可能都是一个简单的好主意,但不太可能在性能上产生很大差异。

尽管如此,还是值得检查一下您是否确实 I /
O约束,而不仅仅是猜测。运行程序,查看您的CPU使用率是接近0%还是接近100%还是一个核心。执行Amadan在注释中建议的操作,然后仅pass出于处理目的运行您的程序,看看这是减少5%的时间还是减少70%的时间。你甚至可以尝试用遍历比较os.openos.read(1024*1024)什么的,看看这是任何更快。


由于您使用的是Python 2.x,因此Python依靠C
stdio库来一次猜测要缓冲多少,因此可能值得强迫它缓冲更多。最简单的方法是使用readlines(bufsize)一些大型的bufsize。(您可以尝试使用不同的数字进行测量,以查看峰值在哪里。根据我的经验,通常从64K-8MB的任何东西都差不多,但是取决于您的系统可能有所不同,尤其是如果您正在阅读网络文件系统具有很高的吞吐量,但可怕的延迟使实际物理驱动器的吞吐量与等待时间相比变得无能为力,而操作系统的缓存也是如此。)

因此,例如:

bufsize = 65536
with open(path) as infile: 
    while True:
        lines = infile.readlines(bufsize)
        if not lines:
            break
        for line in lines:
            process(line)

同时,假设您使用的是64位系统,则可能首先要尝试使用mmap而不是读取文件。当然不能
保证 会更好,但是 可能 会更好,具体取决于您的系统。例如:

with open(path) as infile:
    m = mmap.mmap(infile, 0, access=mmap.ACCESS_READ)

Pythonmmap有点像一个怪异的对象,它的作用类似于strfile,因此,例如,您可以手动迭代扫描换行符,也可以readline像对待文件一样对其进行调用。与将文件作为行或批处理进行迭代相比,这两种方法都将需要更多的Python处理readlines(因为C语言中的循环现在在纯Python中……尽管也许可以使用re或使用简单的Cython扩展来解决该问题?)
…但是,操作系统知道您正在使用映射进行操作的I / O优势可能会淹没CPU的劣势。

不幸的是,Python并未公开madvise您用于调整事物以优化C语言的调用(例如,显式设置MADV_SEQUENTIAL而不是让内核猜测或强制透明大页面),但实际上您可以使用ctypes该函数出libc

2020-12-20