在Python中最小化内存密集操作的磁盘读写

17 投票
11 回答
3627 浏览
提问于 2025-04-17 02:03

背景

我正在做一个计算量比较大的项目,属于计算语言学的范畴。不过,我遇到的问题比较普遍,所以我觉得解决方案对其他人也会有帮助。

需求

我需要写的这个程序有几个关键点:

  1. 要处理一个很大的文本库(大小在5G到30G之间,未来可能会更大)
  2. 逐行处理这些数据。
  3. 从处理后的数据中,构建大量的向量(有些向量的维度超过4,000,000)。通常需要构建数十万个这样的向量。
  4. 这些向量必须以某种格式保存到磁盘上。

步骤1和2相对简单,只要使用生成器和数据分析管道就可以高效完成。真正的大问题在于步骤3(以及相关的步骤4)。

插入:技术细节

如果构建向量的具体过程会影响解决方案:

对于文本库中的每一行,必须更新一个或多个向量的基础权重。

可以把它们想象成Python中的列表,每处理一行,就会更新一个或多个列表(如果需要的话会创建新的列表),通过在一个或多个索引位置增加这些列表的值(这个值可能根据索引不同而不同)。

这些向量之间没有依赖关系,读取文本库的顺序也无关紧要。

尝试的解决方案

在处理这个问题时,有三种极端的选择:

  1. 我可以把所有向量都放在内存中,然后再写入磁盘。
  2. 我可以直接在磁盘上构建所有向量,使用pickle库或类似的工具。
  3. 我可以一次在内存中构建一个向量,然后写入磁盘,每个向量都要遍历一次文本库。

这三种选择都不太可行。第一种会占用所有系统内存,导致系统崩溃和变得非常慢。第二种因为IO操作太慢,所以效率低下。第三种可能比第二种还慢,原因是一样的。

目标

一个好的解决方案应该包括:

  1. 尽可能多地在内存中构建。
  2. 一旦内存满了,就把所有内容写入磁盘。
  3. 如果需要从磁盘中获取数据,就把它们恢复到内存中,以便添加到向量中。
  4. 重复步骤1,直到所有向量都构建完成。

问题是我不太确定该如何进行。担心系统属性(比如内存)似乎有点不符合Python的风格,但我觉得不考虑这些问题就很难找到最佳解决方案。因此,我不知道该如何开始。

问题

有没有人知道该如何解决这个问题?Python是否不适合这种情况?或者有没有简单的方法来最大化内存使用(在合理范围内),同时最小化从磁盘读取或写入数据的次数?

非常感谢你的关注。我期待看到StackOverflow的聪明人们能给我提供什么建议。

附加细节

这个问题运行的机器通常有20个以上的核心和大约70G的内存。这个问题可以进行并行处理(类似MapReduce),即可以从文本库的不同部分构建一个实体的独立向量,然后将它们合并,得到从整个文本库构建的向量。

部分问题涉及确定在需要写入磁盘之前,内存中可以构建多少内容。Python是否提供了某种机制来确定可用的内存?

11 个回答

2

可以考虑使用现有的内存数据库解决方案,比如Redis。当内存用完后,切换到硬盘的这个问题以及一些调整这个过程的小技巧应该已经有了。Python也有相应的客户端。

而且,这个解决方案在扩展上也比较简单,不需要太多的努力。

3

这里有几个库,你可能想要了解一下:

  • joblib - 这个库可以让你轻松进行并行计算,还能自动把输出结果存到磁盘上,方便以后使用,而且在需要的时候才重新计算。

  • mrjob - 这个库让你在亚马逊的弹性MapReduce或者你自己的Hadoop集群上,编写Hadoop流处理任务变得简单。

6

看看 pytables。它的一个优点是,你可以像在内存中一样,处理存储在硬盘上的大量数据。

补充一下:因为输入输出的性能可能会成为瓶颈(如果不是唯一的瓶颈的话),所以你可能需要考虑使用固态硬盘(SSD)技术:它每秒能处理很多输入输出,而且几乎没有寻址时间。你的项目大小非常适合现在价格合理的SSD硬盘。

撰写回答