如何有效地读取和写入太大而无法放入内存的文件?

Joj*_*ing 19 python memory-management numpy

我试图计算100,000个向量的余弦相似度,并且这些向量中的每一个都有200,000个维度.

从阅读其他问题我知道memmap,PyTables和h5py是我处理这类数据的最佳选择,我目前正在使用两个memmaps; 一个用于读取矢量,另一个用于存储余弦相似性矩阵.

这是我的代码:

import numpy as np
import scipy.spatial.distance as dist

xdim = 200000
ydim = 100000

wmat = np.memmap('inputfile', dtype = 'd', mode = 'r', shape = (xdim,ydim))
dmat = np.memmap('outputfile', dtype = 'd', mode = 'readwrite', shape = (ydim,ydim))

for i in np.arange(ydim)):
    for j in np.arange(i+1,ydim):
        dmat[i,j] = dist.cosine(wmat[:,i],wmat[:,j])
        dmat.flush()
Run Code Online (Sandbox Code Playgroud)

目前,htop报告说我正在使用224G的VIRT内存,而91.2G的RES内存正在稳步攀升.在我看来,在整个过程结束时,整个输出矩阵将存储在内存中,这是我试图避免的.

问:这是memmaps的正确用法,我在记忆有效的方式写入到输出文件(我的意思是,只有输入和输出文件的必要部分,即dmat[i,j]wmat[:,i/j],存储在内存中)?

如果没有,我做错了什么,我该如何解决这个问题呢?

感谢您的任何建议!

编辑:我刚刚意识到htop报告的总体系统内存使用量为12G,所以它似乎正在起作用......那里有谁可以开导我?RES现在是111G ......

编辑2:memmap是从一维数组创建的,该数组由很多很长的小数组成,非常接近于0,形状符合所需的尺寸.然后memmap看起来像这样.

memmap([[  9.83721223e-03,   4.42584107e-02,   9.85033578e-03, ...,
     -2.30691545e-07,  -1.65070799e-07,   5.99395837e-08],
   [  2.96711345e-04,  -3.84307391e-04,   4.92968462e-07, ...,
     -3.41317722e-08,   1.27959347e-09,   4.46846438e-08],
   [  1.64766260e-03,  -1.47337747e-05,   7.43660202e-07, ...,
      7.50395136e-08,  -2.51943163e-09,   1.25393555e-07],
   ..., 
   [ -1.88709000e-04,  -4.29454722e-06,   2.39720287e-08, ...,
     -1.53058717e-08,   4.48678211e-03,   2.48127260e-07],
   [ -3.34207882e-04,  -4.60275148e-05,   3.36992876e-07, ...,
     -2.30274532e-07,   2.51437794e-09,   1.25837564e-01],
   [  9.24923862e-04,  -1.59552854e-03,   2.68354822e-07, ...,
     -1.08862665e-05,   1.71283316e-07,   5.66851420e-01]])
Run Code Online (Sandbox Code Playgroud)

ali*_*i_m 8

就内存使用而言,目前您正在做的事情没有什么特别的错误.Memmap数组在OS级别处理 - 要写入的数据通常保存在临时缓冲区中,并且只在OS认为必要时才提交到磁盘.在刷新写缓冲区之前,您的操作系统绝不允许您耗尽物理内存.

我建议不要flush在每次迭代时调用,因为这会让你的操作系统决定何时写入磁盘以最大限度地提高效率.目前,您只是一次编写单个浮点值.


就IO和CPU效率而言,一次在单行上运行几乎肯定不是最理想的.对于大的,连续的数据块,读取和写入通常更快,如果使用向量化可以一次处理多行,则计算速度可能会快得多.一般的经验法则是处理数组中适合内存的大块(包括计算过程中创建的任何中间数组).

这是一个示例,显示了通过在适当大小的块中处理它们可以加快memmapped阵列上的操作速度.

另一个可以产生巨大差异的是输入和输出数组的内存布局.默认情况下,np.memmap为您提供C-contiguous(行主要)数组.wmat因此,按列访问将非常低效,因为您正在寻址磁盘上的非相邻位置.如果wmat在磁盘上是F-contiguous(列主要),或者如果你是按行访问它,那么你会好得多.

相同的一般建议适用于使用HDF5而不是memmaps,但请记住,使用HDF5时,您必须自己处理所有内存管理.

  • 速度,压缩,便携性...... Joe Kington的答案[这里](http://stackoverflow.com/a/27713489/1461210)在覆盖优缺点方面做得非常好. (2认同)

Dan*_*iel 7

内存映射正如名称所示:将(虚拟)磁盘扇区映射到内存页面.内存由操作系统按需管理.如果有足够的内存,系统会将部分文件保留在内存中,可能会填满整个内存,如果没有足够的内存,系统可能会丢弃从文件中读取的页面,或者可能将它们交换到交换空间.通常,您可以依赖OS尽可能高效.