是的,我正在迭代一个大的二进制文件
我需要最小化这个循环的时间:
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中创建索引位置列表,我使用此函数浏览,然后“搜索”到绝对位置 - 这是否有效?
干杯
答案 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加载它将在循环优化之前为您提供大量的速度增益。