python - 在 Python 中读取和切片二进制数据文件的最快方法

标签 python matlab performance python-2.7 numpy

我有一个处理脚本,旨在提取“uint16”类型的二进制数据文件,并一次以 6400 个 block 为单位进行各种处理。代码最初是用 Matlab 编写的,但由于分析代码是用 Python 编写的,我们希望通过在 Python 中完成所有操作来简化流程。问题是我注意到我的 Python 代码比 Matlab 的 fread 函数慢得多。

简单的说Matlab代码是这样的:

fid = fopen(filename); 
frame = reshape(fread(fid,80*80,'uint16'),80,80);  

虽然我的 Python 代码很简单:

with open(filename, 'rb') as f: 
    frame = np.array(unpack("H"*6400, f.read(12800))).reshape(80, 80).astype('float64')

文件大小从 500 MB 到 400 GB 不等,因此我相信找到一种用 Python 解析数据的更快方法可以为更大的文件带来好处。 500 MB 通常有大约 50000 个 block ,这个数字随文件大小线性增加。我看到的速度差异大致是:

Python = 4 x 10^-4 seconds / chunk

Matlab = 6.5 x 10^-5 seconds / chunk

随着时间的推移,处理显示 Matlab 比我实现的 Python 方法快约 5 倍。我已经探索过 numpy.fromfile 和 numpy.memmap 等方法,但由于这些方法需要在某个时候将整个文件打开到内存中,因此它限制了用例,因为我的二进制文件非常大。是否有一些我缺少的 pythonic 方法来执行此操作?我原以为 Python 在打开和读取二进制文件时会非常快。任何意见是极大的赞赏。

最佳答案

将 block 写入文件:

In [117]: dat = np.random.randint(0,1028,80*80).astype(np.uint16)
In [118]: dat.tofile('test.dat')
In [119]: dat
Out[119]: array([266, 776, 458, ..., 519,  38, 840], dtype=uint16)

按您的方式导入:

In [120]: import struct
In [121]: with open('test.dat','rb') as f:
     ...:     frame = np.array(struct.unpack("H"*6400,f.read(12800)))
     ...:     
In [122]: frame
Out[122]: array([266, 776, 458, ..., 519,  38, 840])

使用 fromfile 导入

In [124]: np.fromfile('test.dat',count=6400,dtype=np.uint16)
Out[124]: array([266, 776, 458, ..., 519,  38, 840], dtype=uint16)

比较时间:

In [125]: %%timeit
     ...:  with open('test.dat','rb') as f:
     ...:      ...:     frame = np.array(struct.unpack("H"*6400,f.read(12800)))
     ...: 
1000 loops, best of 3: 898 µs per loop

In [126]: timeit np.fromfile('test.dat',count=6400,dtype=np.uint16)
The slowest run took 5.41 times longe....
10000 loops, best of 3: 36.6 µs per loop

fromfile 快得多。

struct.unpack 的时间,没有 np.array 是 266 µs;对于 f.read,23。所以它是 unpack 加上更通用和更强大的 np.array 花费了更长的时间。文件读取本身不是问题。 (np.array 可以处理多种输入,列表的列表,对象的列表等,因此必须花更多的时间来解析和评估输入。)

fromfile 的一个稍快的变体是你的阅读加上 frombuffer:

In [133]: with open('test.dat','rb') as f:
     ...:      frame3 = np.frombuffer(f.read(12800),dtype=np.uint16)

关于python - 在 Python 中读取和切片二进制数据文件的最快方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44169233/

相关文章:

python - 是否可以构建一个程序来确定另一个 python 程序正在使用哪些库?

algorithm - 调整算法?

matlab - R中的秒表功能

php - 异步搜索事件处理

sql - LEFT JOIN 明显快于 INNER JOIN

python - 无法嵌入 python 以使用压缩库

python - 迭代 XML 标签并在 Python 中获取元素的 xpath

Python Twisted 如何使用新的 IPolicyForHTTPS 为 twisted.web.client.Agent 设置 SSL 方法?

python - 如何使用逻辑运算符访问和更改 Python 数组?

java - 如何使用 currentTimeMillis() 在类上运行计算速度?