2013-03-12 56 views
4

我想用cython編譯一個python函數,用於讀取跳過一些記錄的二進制文件(不需要讀取整個文件然後切片,因爲我將耗盡內存)。我能想出這樣的事情:將文件句柄傳遞給cython函數

def FromFileSkip(fid, count=1, skip=0):    
     if skip>=0: 
      data = numpy.zeros(count) 
      k = 0 
      while k<count: 
       try: 
        data[k] = numpy.fromfile(fid, count=1, dtype=dtype) 
        fid.seek(skip, 1) 
        k +=1 
       except ValueError: 
        data = data[:k] 
        break 
      return data 

,然後我可以使用這樣的功能:

f = open(filename) 
data = FromFileSkip(f,... 

然而,對於編制功能「FromFileSkip」與用Cython,我想定義函數中涉及的所有類型,所以「fid」也是文件處理程序。我如何在cython中定義它的類型,因爲它不是「標準」類型,例如一個整數。 謝謝。

+3

爲什麼鍵入該變量很重要?由於它是一個python對象,你不會獲得任何加速。 – Bakuriu 2013-03-12 08:44:33

+0

如果要將其分配給類變量,則使用'object'類型。 – 2013-03-12 09:10:12

+1

因此,輸入文件句柄不會有太大改變?我認爲無需例外地輸入所有變量,與僅輸入一些變量相比,性能得到提高。 – user2061949 2013-03-12 09:53:08

回答

5

定義fid的類型將無濟於事,因爲調用python函數的代價依然很高。嘗試使用「-a」標誌編譯您的示例以瞭解我的意思。但是,您可以使用低級C函數進行文件處理,以避免循環中出現python開銷。例如起見,我假定該數據正確的從文件的開頭開始,其類型爲double

from libc.stdio cimport *                 

cdef extern from "stdio.h": 
    FILE *fdopen(int, const char *) 

import numpy as np 
cimport numpy as np 

DTYPE = np.double # or whatever your type is 
ctypedef np.double_t DTYPE_t # or whatever your type is 

def FromFileSkip(fid, int count=1, int skip=0): 
    cdef int k 
    cdef FILE* cfile 
    cdef np.ndarray[DTYPE_t, ndim=1] data 
    cdef DTYPE_t* data_ptr 

    cfile = fdopen(fid.fileno(), 'rb') # attach the stream 
    data = np.zeros(count).astype(DTYPE) 
    data_ptr = <DTYPE_t*>data.data 

    # maybe skip some header bytes here 
    # ... 

    for k in range(count): 
     if fread(<void*>(data_ptr + k), sizeof(DTYPE_t), 1, cfile) < 0: 
      break 
     if fseek(cfile, skip, SEEK_CUR): 
      break 

    return data 

注意的cython -a example.pyx輸出顯示了環內沒有蟒蛇的開銷。