Jul*_*ian 0 python arrays distutils cython
我有一个大型二进制数据文件,我想将其加载到 C 数组中以便快速访问。数据文件仅包含 4 字节整数序列。
我通过 pkgutil.get_data 函数获取数据,该函数返回一个二进制字符串。以下代码有效:
import pkgutil
import struct
cdef int data[32487834]
def load_data():
global data
py_data = pkgutil.get_data('my_module', 'my_data')
for i in range(32487834):
data[i] = <int>struct.unpack('i', py_data[4*i:4*(i+1)])[0]
return 0
load_data()
Run Code Online (Sandbox Code Playgroud)
问题是这段代码非常慢。读取整个数据文件可能需要 7 或 8 秒。将文件直接读入 C 中的数组只需 1-2 秒,但我想使用 pkgutil.get_data 以便我的模块无论安装在何处都可以可靠地找到数据。
所以,我的问题是:最好的方法是什么?有没有办法直接将数据转换为整数数组,而不需要对 struct.unpack 进行所有调用?而且,作为第二个问题,有没有一种方法可以简单地获取指向数据的指针,以避免不必要地复制 120MB 的数据?
或者,有没有办法让 pkgutil 返回数据的文件路径而不是数据本身(在这种情况下,我可以使用 C 文件 IO 来快速读取文件。
编辑:
仅供记录,这是最终使用的代码(基于 Veedrac 的答案):
import pkgutil
from cpython cimport array
import array
cdef int[:] data
cdef void load_data():
global data
py_data = pkgutil.get_data('my_module', 'my_data')
data = array.array('i', py_data)
load_data()
Run Code Online (Sandbox Code Playgroud)
一切都很快。
您可能真的应该只使用 Numpy:
import numpy
import random
import struct
data = struct.pack('i'*100, *[random.randint(0, 1000000) for _ in range(100)])
numpy.fromstring(data, dtype="int32")
#>>> array([642029, 967046, 599565, ...etc], dtype=int32)
Run Code Online (Sandbox Code Playgroud)
然后只需使用任何标准方法即可从中获取指针。
如果你想避免 Numpy,一种更快但与平台无关的方法是通过 char 指针:
cdef int *data_view = <int *><char *>data
Run Code Online (Sandbox Code Playgroud)
这有很多“未定义”的地方,所以要小心。另外注意不要修改数据!
两者之间的一个很好的折衷方案是使用cpython.array:
from cpython cimport array
import array
def main(data):
cdef array.array[int] data_arr = array.array('i', data)
cdef int *data_ptr = data_arr.data.as_ints
Run Code Online (Sandbox Code Playgroud)
它为您提供了明确定义的语义,并且内置库的速度很快。
| 归档时间: |
|
| 查看次数: |
2390 次 |
| 最近记录: |