在Python中处理多个大文件
我有大约60个文件,每个文件大概有90万行,每一行包含17个用制表符分隔的浮点数。对于每一行,我需要用所有60个文件中对应的行来进行一些计算。但是因为这些文件太大了(每个文件大约400MB),而且我的计算资源有限,所以花费的时间很长。我想知道有没有什么办法可以更快地完成这个计算?
3 个回答
这里有几个选项:
1. 直接使用内存
如果你有17x900000 = 15.3百万个浮点数每个文件。把这些存成双精度浮点数(通常numpy
会这样做)大约会占用每个文件120MB的内存。你可以通过把浮点数存成float32
来减少这个占用,这样每个文件大约只需要60MB。如果你有60个文件,每个60MB,那就是3.6GB的数据。
这个数据量在使用64位的Python时是可以接受的。如果你的机器内存少于6GB,比如说,那就会频繁使用虚拟内存。是否会造成问题,取决于你访问数据的方式。
2. 一行一行地处理
如果可以一行一行地处理,那就每次读取一个文件的一行。打开60个文件是很简单的,这不会造成任何问题。如果你按顺序处理文件,这可能是最有效的方法。内存使用几乎可以忽略不计,操作系统会负责读取文件。
操作系统和底层的文件系统在顺序读取和写入磁盘时非常努力地提高效率。
3. 预处理你的文件并使用mmap
你也可以预处理你的文件,把它们从CSV格式转换成二进制格式。这样每一行在文件中会占用17x8 = 136字节或17x4 = 68字节。然后你可以使用numpy.mmap
将文件映射成[N, 17]形状的数组。你可以像处理普通数组一样处理这些数组,numpy
和操作系统会负责优化内存管理。
预处理是必要的,因为文本文件中每行的长度(字符数)是不固定的。
如果你的数据访问不是顺序的,这可能是最好的解决方案。然后mmap
是最快的方法,因为它只在需要时从磁盘读取所需的块。它还会缓存数据,从而使用最优的内存量。
在后台,这与第一种解决方案非常相似,唯一的区别是,直到需要时才会加载到内存中。关于32位Python的限制依然适用;它无法做到这一点,因为它的内存地址不够用。
将文件转换为二进制格式相对快速且简单,几乎只需一行代码。
如果“对应的行”是指“所有文件的第一行,然后是所有文件的第二行,依此类推”,你可以使用 `itertools.izip`:
# cat f1.txt
1.1
1.2
1.3
# cat f2.txt
2.1
2.2
2.3
# python
>>> from itertools import izip
>>> files = map(open, ("f1.txt", "f2.txt"))
>>> lines_iterator = izip(*files)
>>> for lines in lines_iterator:
... print lines
...
('1.1\n', '2.1\n')
('1.2\n', '2.2\n')
('1.3\n', '2.3\n')
>>>
这要看你怎么处理这些文件。如果你的内存足够大,可以先把所有文件都读进来,然后把它们转换成Python的数据结构。这样你就可以进行计算了。
如果你的文件太大,放不进内存,最简单的方法可能是使用一些分布式计算的工具,比如Hadoop或者其他更轻量级的选择。
还有一些小的改进可以尝试,比如使用Linux的fadvice函数,告诉系统你打算怎么使用这个文件(是顺序读取还是随机访问),这样可以帮助操作系统优化文件的访问速度。
如果你的计算可以用一些常见的库,比如numpy或numexpr,这些库有很多优化,可以帮助你更高效地处理数据(这对于那些没有优化的算法来说特别有用)。