2014-11-06 3 views
0

빠른 액세스를 위해 C 배열에로드하려는 큰 바이너리 데이터 파일이 있습니다. 데이터 파일에는 4 바이트 int 시퀀스가 ​​포함됩니다.바이너리 문자열을 int 배열로 변환하는 Cython 빠른 변환

이진 문자열을 반환하는 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를 사용하여 모듈이 설치 될 때마다 데이터를 안정적으로 찾을 수 있습니다.

제 질문은 이렇게하는 것입니다.이 작업을 수행하는 가장 좋은 방법은 무엇입니까? struct.unpack에 대한 호출없이 int 배열로 데이터를 직접 캐스팅 할 수 있습니까? 그리고 2 차 질문으로 120MB의 데이터를 불필요하게 복사하지 않도록 데이터에 대한 포인터를 얻는 방법이 있습니까?

또는, 나는 매우 빠르게 파일을 읽을 C 파일 IO를 사용할 수있는 경우 대신 데이터 자체의 데이터에 대한 파일 경로를 (반환 pkgutil 만들 수있는 방법이

편집 :.

그냥 레코드에 대한

은 여기 (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

그냥 메모리 맵이 아닌가? –

답변

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

감사! 두 번째 방법은 아름답게 작동했습니다. 이 작업을 효율적으로 수행 할 수있는 방법이 있어야한다는 것을 알고있었습니다. 내가 가비지를 수집하지 않도록 전역 범위에서 바이트의 복사본을 보관해야한다고 가정 할 때 맞습니까? 플랫폼 문제가 해결 될 때 일부 플랫폼에서는 32 비트 int를 사용할 수 없다는 문제가 있습니까? 실제로 문제가 될 가능성이 있습니까? 아니면 이론적 인 관심사일까요? – Julian

+1

두 번째 경우에는 예. 다른 사람들은 복사를하지만 (매우 빠릅니다). 'numpy.frombuffer'를 사용하면 첫 번째 복사본을 복사하지 않을 수 있습니다. // 두 번째로 잠재적 인 문제가 많습니다. 실제로 어떤 동작이 정의되어 있지 않습니다. 컴파일러와 플랫폼이 합리적인 것을 만들었다 고 가정한다면, 여전히 엔디안과 int의 크기에 대해 걱정할 필요가 있습니다. 운 좋게도 관계없이 대부분의 시간 동안 작동 할 것입니다. 다른 endiannesses 나 다른 크기의'int'를 사용하는 플랫폼이 있습니다. – Veedrac

+0

내가 할 수 있으면 나는 확실히 numpy를 피하려고 노력하고있다. 접근을 위해서는 cpython 배열이 똑같은 빠른 c- 배열만큼 빠릅니까? 로딩 시간이 1 초 미만이고 액세스가 빠르면 로딩 시간이 약간 더 길어도 상관하지 않습니다. – Julian

관련 문제