Python:通过大文件迭代这个的最快方法

时间:2010-02-23 16:39:51

标签: python binary numpy iteration

是的,我正在迭代一个大的二进制文件

我需要最小化这个循环的时间:

def NB2(self, ID_LEN):
    r1=np.fromfile(ReadFile.fid,dTypes.NB_HDR,1)
    num_receivers=r1[0][0]
    num_channels=r1[0][1]
    num_samples=r1[0][5]

    blockReturn = np.zeros((num_samples,num_receivers,num_channels))

    for rec in range(0,num_receivers):
        for chl in range(0,num_channels):
            for smpl in range(0,num_samples):
                r2_iq=np.fromfile(ReadFile.fid,np.int16,2)
                blockReturn[smpl,rec,chl] = np.sqrt(math.fabs(r2_iq[0])*math.fabs(r2_iq[0]) + math.fabs(r2_iq[1])*math.fabs(r2_iq[1]))

    return blockReturn

所以,发生的事情如下: r1是文件的标题,dTypes.NB_HDR是我制作的类型:

NB_HDR= np.dtype([('f3',np.uint32),('f4',np.uint32),('f5',np.uint32),('f6',np.int32),('f7',np.int32),('f8',np.uint32)])

它获取有关即将到来的数据块的所有信息,并很好地将我们放在文件中的正确位置(数据块的开头!)。

在此数据块中有: 每通道4096个样本, 每个接收器4个通道, 9个接收器。

所以num_receivers,num_channels,num_samples将始终是相同的(此时此刻),但正如您所看到的,这是一个相当大量的数据。每个'样本'是一对int16值,我想找到它的大小(因此毕达哥拉斯)。

对于文件中的每个“块”执行此NB2代码,对于12GB文件(它有多大),大约有20,900个块,我必须遍历1000个这些文件(所以,总共12TB)。任何速度优势,即使是毫秒,也会受到大力赞赏。

编辑:实际上,了解我如何在文件中移动可能会有所帮助。我的功能如下:

def navigateTo(self, blockNum, indexNum):
    ReadFile.fid.seek(ReadFile.fileIndex[blockNum][indexNum],0)
    ReadFile.currentBlock = blockNum
    ReadFile.index = indexNum

在运行所有这些代码之前,我扫描文件并在ReadFile.fileIndex中创建索引位置列表,我使用此函数浏览,然后“搜索”到绝对位置 - 这是否有效?

干杯

5 个答案:

答案 0 :(得分:3)

import numpy as np
def NB2(self, ID_LEN):
    r1=np.fromfile(ReadFile.fid,dTypes.NB_HDR,1)
    num_receivers=r1[0][0]
    num_channels=r1[0][1]
    num_samples=r1[0][5]

    # first, match your array bounds to the way you are walking the file
    blockReturn = np.zeros((num_receivers,num_channels,num_samples))

    for rec in range(0,num_receivers):
        for chl in range(0,num_channels):
            # second, read in all the samples at once if you have enough memory
            r2_iq=np.fromfile(ReadFile.fid,np.int16,2*num_samples)
            r2_iq.shape = (-1,2) # tell numpy that it is an array of two values

            # create dot product vector by squaring data elementwise, and then
            # adding those elements together.  Results is of length num_samples
            r2_iq = r2_iq * r2_iq
            r2_iq = r2_iq[:,0] + r2_iq[:,1]
            # get the distance by performing the square root "into" blockReturn
            np.sqrt(r2_iq, out=blockReturn[rec,chl,:])

    return blockReturn

这应该有助于您的表现。 numpy工作中的两个主要思想。首先,对于内存位置,您的结果数组维度应与您的循环维度的制作方式相匹配 其次,Numpy FAST 。我用numpy手动编码C,仅仅是因为它使用了LAPack和矢量加速。但是要获得这种能力,你必须让它一次操纵更多的数据。这就是为什么你的样本循环已被折叠,以便在一次大读取中读取接收器和通道的完整样本。然后使用numpy的 supreme vector powers 来计算你的数量。

在量值计算中还有一些优化,但是numpy会为你回收缓冲,使它不如你想象的那么重要。我希望这有帮助!

答案 1 :(得分:3)

因为您在读取标题后知道块的长度,所以立即读取整个块。然后重塑数组(非常快,只影响元数据)并使用np.hypot ufunc:

blockData = np.fromfile(ReadFile.fid, np.int16, num_receivers*num_channels*num_samples*2)
blockData = blockData.reshape((num_receivers, num_channes, num_samples, 2))
return np.hypot(blockData[:,:,:,0], blockData[:,:,:,1])

在我的机器上,它每块运行11毫秒。

答案 2 :(得分:1)

我尝试使用尽可能少的循环和尽可能多的常量。 应该以线性方式完成所有工作。 如果值没有改变,使用常量来减少查找等, 因为这会占用cpu周期。

这是从理论的角度来看; - )

如果可能,请使用高度优化的库。我并不知道你想要实现什么,但我宁愿使用现有的FFT-Lib而不是自己编写:>

还有一件事:http://en.wikipedia.org/wiki/Big_O_notation(可能令人大开眼界)

答案 3 :(得分:1)

最重要的是,无论是在C语言还是Python中,都不应该在三重嵌套循环的最低级别进行文件访问。你必须一次读取大块数据。

因此,为了加快速度,一次读入大块数据,并使用numpy索引处理该数据(即向量化代码)。这在您的情况下特别容易,因为您的所有数据都是int32。只需读入大块数据,然后将数据重新整形为反映(接收器,通道,样本)结构的数组,然后使用适当的索引来为Pythagoras增加和添加内容,并使用'sum'命令加总结果数组中的术语。

答案 4 :(得分:0)

这更像是一个观察而不是解决方案,但是将该函数移植到C ++并使用Python API加载它将在循环优化之前为您提供大量的速度增益。