2014-11-06 118 views
0

我有一个较大的二进制数据文件,我想将它加载到C数组中以便快速访问。数据文件只包含4个字节的整数。Cython将二进制字符串快速转换为int数组

我通过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() 

的问题是,这个代码是相当缓慢。读取整个数据文件可能需要7或8秒。将文件直接读入C中的数组只需要1-2秒,但我想使用pkgutil.get_data,这样我的模块就可以可靠地找到安装它的数据。

所以,我的问题是:什么是最好的方法来做到这一点?有没有一种方法可以直接将数据转换为int数组而无需对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() 

一切是相当快的

+0

为什么不只是记忆地图呢? – 2014-11-06 16:53:42

回答

2

机会是你应该真的只是使用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) 

然后只是使用任何的standard methods to get a pointer from that

如果你想避免numpy的,快,但不能与平台无关的方法是通过一个字符指针走:

cdef int *data_view = <int *><char *>data 

这有很多“不确定” -ness给它的,所以要小心。另外要小心不要修改数据!

两者之间的良好compromize是使用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 

它给你明确的语义和快速与内置库。

+0

谢谢!第二种方法工作得很好。我知道必须有一种方法可以有效地做到这一点。我是否正确地假设我必须在全局范围内保留bytestring的副本,以免它被垃圾收集?就平台问题而言,问题在于某些平台可能不使用32位整数?这实际上可能是一个真正的问题吗?或者只是理论上的关注? – Julian 2014-11-06 17:28:27

+1

对于第二种情况,是的。其他人复制(但速度非常快)。你可以使用'numpy.frombuffer'来获得第一个非复制变体。 //第二个问题有很多潜在的问题:它实际上没有定义*根本就没有*行为是什么。假设编译器和平台使它做了一些明智的事情,你仍然需要考虑endianness和int的大小。幸运的是,无论如何,它大多数时间都可以工作,但这并不是必需的。有些平台使用不同的字节序或不同大小的'int',所以这取决于你是否关心它们! – Veedrac 2014-11-06 17:35:58

+0

如果可以的话,我一定要尽量避免numpy。访问cpython数组的速度与直c数组一样快吗?我并不在乎加载时间是否稍长,只要<1s并且访问速度很快。 – Julian 2014-11-06 18:21:12

相关问题