提高从二进制文件读取和转换的速度?

hel*_*ker 13 python performance file-io

我知道有一些关于文件读取,二进制数据处理和使用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']))])
Run Code Online (Sandbox Code Playgroud)

有了这段代码,我得到每兆字节读取2.2秒,带有2Mb RAM的双核,而我的文件通常有20+ Mb,这会产生一些非常恼人的延迟(特别考虑到另一个基准共享软件程序我试图镜像加载文件快点吧.

我想知道的是:

  1. 如果有一些违反"良好做法"的行为:错误安排的循环,重复性操作需要的时间超过必要时间,使用低效的容器类型(字典?)等.
  2. 如果这个读取速度正常,或者是Python正常,并且读取速度快
  3. 如果创建C++编译的扩展可能会提高性能,并且如果它是推荐的方法.
  4. (当然)如果有人建议对此代码进行一些修改,最好根据之前的类似操作经验.

谢谢阅读

(我已经发布了一些关于我的这个职位的问题,我希望它们在概念上都是无关的,我也希望不要过于重复.)

编辑: channel_names是一个列表,所以我做了@eumiro建议的修正(删除错误的括号)

编辑:我目前使用的塞巴斯蒂安的建议去arrayfromfile()方法,并将很快把这里的最终代码.此外,每一个结果对我都非常有用,我非常高兴地感谢所有善意回答的人.

进入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
Run Code Online (Sandbox Code Playgroud)

与一次读取文件或以任何形式使用文件相比,速度提升非常令人印象深刻struct.

jfs*_*jfs 15

您可以array用来读取您的数据:

import array
import os

fn = 'data.bin'
a = array.array('h')
a.fromfile(open(fn, 'rb'), os.path.getsize(fn) // a.itemsize)
Run Code Online (Sandbox Code Playgroud)

它比快40个倍struct.unpack@ samplebias的答案.


sam*_*ias 7

如果文件只有20-30M,为什么不读取整个文件,在一次调用中解码nums unpack,然后通过遍历数组在你的通道中分配它们:

data = open('data.bin', 'rb').read()
values = struct.unpack('%dh' % len(data)/2, data)
del data
# iterate over channels, and assign from values using indices/slices
Run Code Online (Sandbox Code Playgroud)

快速测试显示,这导致struct.unpack('h', f.read(2))20M文件的速度提高了10倍.