我知道以前有一些关于文件读取、二进制数据处理和使用struct
进行整数转换的问题,所以我来这里询问一段代码,我认为这段代码运行时间太长了。正在读取的文件是一个多通道数据样本记录(短整数),其中包含数据间隔(因此是嵌套的for
语句)。代码如下:
# channel_content is a dictionary, channel_content[channel]['nsamples'] is a string
for rec in xrange(number_of_intervals)):
for channel in channel_names:
channel_content[channel]['recording'].extend(
[struct.unpack( "h", f.read(2))[0]
for iteration in xrange(int(channel_content[channel]['nsamples']))])
有了这段代码,我每兆字节读取2.2秒,双核内存为2 Mb,我的文件通常有20+Mb,这会带来一些非常烦人的延迟(特别是考虑到另一个基准共享软件程序,我正试图以更快的速度镜像加载文件)。
我想知道的是:
谢谢你的阅读
(我已经发布了一些关于我这项工作的问题,我希望它们在概念上都不相关,我也希望不要太重复。)
Edit:channel_names
是一个列表,因此我做了@eumiro建议的更正(删除键入的括号)
编辑:我现在同意塞巴斯蒂安的建议,将array
与fromfile()
方法一起使用,并很快将最终代码放在这里。此外,每一个贡献对我都非常有用,我非常高兴地感谢每一个善意的回答。
使用array.fromfile()
一次,然后通过切片大数组为每个通道交替扩展一个数组后的最终形式:
fullsamples = array('h')
fullsamples.fromfile(f, os.path.getsize(f.filename)/fullsamples.itemsize - f.tell())
position = 0
for rec in xrange(int(self.header['nrecs'])):
for channel in self.channel_labels:
samples = int(self.channel_content[channel]['nsamples'])
self.channel_content[channel]['recording'].extend(
fullsamples[position:position+samples])
position += samples
每次读取一点文件,或者以任何形式使用struct
,速度的提高都令人印象深刻。
如果文件只有20-30M,为什么不读取整个文件,在对
unpack
的单个调用中解码nums,然后通过迭代数组在通道之间分发它们:一项快速测试显示,这导致在20M文件上的速度比
struct.unpack('h', f.read(2))
快10倍。extend()acepts iterables,也就是说,您可以编写
.extend(...)
,而不是.extend([...])
。它可能会加快程序的速度,因为extend()将在生成器上处理,而不再在生成的列表上处理代码中有一个不连贯的地方:首先定义
channel_content = {}
,然后执行channel_content[channel]['recording'].extend(...)
,这需要一个键通道和一个子键“录制”的初始存在,并将一个列表作为一个值,以便能够扩展到某些内容self.channel_content[channel]['nsamples']
的性质是什么,以便它可以提交到int()函数?间隔数从何而来?间隔的性质是什么?
在
rec in xrange(number_of_intervals)):
循环中,我再也看不到rec。因此,在我看来,您重复的循环过程for channel in channel_names:
是由间隔数表示的次数的两倍。是否存在要在f中读取的间隔*int(self.channel_content[channel]['nsamples'])*2个值的个数?我在文件中读到:
这表达了与samplebias相同的思想。
如果您的目标是创建一个字典,那么还可以使用dict()和一个生成器作为参数
是的。
编辑
我提议
我不知道如何考虑J.F.塞巴斯蒂安关于使用数组的建议
您可以使用^{} 读取数据:
它比@samplebias's answer中的
struct.unpack
快40倍。相关问题 更多 >
编程相关推荐