2013-04-29 14 views
21

Python ve Numpy kullanarak bir ses algoritması geliştiriyorum. Şimdi bu algoritmayı C'nin bir parçasını uygulayarak hızlandırmak istiyorum. Geçmişte, I have done this using cython. Şimdi aynı şeyi yeni cffi kullanarak yapmak istiyorum. Bir nump dizisini bir cffi işlevine nasıl geçirirsiniz ve bir tane nasıl çıkartabilirsiniz?

void copy(float *in, float *out, int len) { 
    for (int i=0; i<len; i++) { 
     out[i] = in[i]; 
    } 
} 

Şimdi iki numpy diziler oluşturmak ve bu bu fonksiyonu tarafından işlenecek istiyorum:

test amaçları için, ben önemsiz bir C işlevi yazdı.
  1. doğrudan kopyalama olmadan numpy Dizilerin yatan yüzer tamponlarını erişmek için bir yol var mı: Bu kodu geliştirmek istiyoruz, ancak

    import numpy as np 
    from cffi import FFI 
    
    ffi = FFI() 
    ffi.cdef("void copy(float *in, float *out, int len);") 
    C = ffi.dlopen("/path/to/copy.dll") 
    
    float_in = ffi.new("float[16]") 
    float_out = ffi.new("float[16]") 
    
    arr_in = 42*np.ones(16, dtype=np.float32) 
    
    float_in[0:16] = arr_in[0:16] 
    C.copy(float_in, float_out, 16) 
    arr_out = np.frombuffer(ffi.buffer(float_out, 16*4), dtype=np.float32) 
    

    : Bunu yapmanın bir yolunu onları?

  2. ffi.buffer, bir C dizisinin içeriğine hızlıca Numpy dizisine dönüştürmek için çok uygundur. Tek tek öğeleri kopyalamadan numpy dizisini bir C dizisine dönüştürmek için eşdeğer bir yol var mı?
  3. Bazı uygulamalar için float_in[0:16] = arr_in[0:16], verilere erişmenin kolay bir yoludur. Tersi, arr_out[0:16] = float_out[0:16], ancak çalışmaz. Neden olmasın? ndarray arasında

cevap

19

ctypes özelliği ctypes modülü ile etkileşime girebilir, örneğin, ndarray.ctypes.data dizinin veri adresi, sen, bir float * işaretçi döküm ve ardından C işlev işaretçiyi geçebilir. Sorunuzun 3 için

import numpy as np 
from cffi import FFI 

ffi = FFI() 
ffi.cdef("void copy(float *in, float *out, int len);") 
C = ffi.dlopen("ccode.dll") 

a = 42*np.ones(16, dtype=np.float32) 
b = np.zeros_like(a) 
pa = ffi.cast("float *", a.ctypes.data) 
pb = ffi.cast("float *", b.ctypes.data) 

C.copy(pa, pb, len(a)) 
print b 

:

Ben ffi dizisi, iç tampon var erişmek için gerekli bilgileri numpy sağlamaz düşünüyorum. Bu yüzden numpy, başarısız olan bir float numarasına dönüştürmeyi deneyin.

import numpy as np 
import cffi 
ffi = cffi.FFI() 

a = np.zeros(42) 
data = a.__array_interface__['data'][0] 
cptr = ffi.cast ("double*" , data) 

şimdi bir cffi vardır: o dizi arayüz aracılığıyla

float_in[0:16] = list(arr_in[0:16]) 
12

verileri bir numpy dizide erişilebilir: I can düşündüğü

iyi çözüm ilk listelemek dönüştürmek olduğunu Kopyalama rutininize iletebileceğiniz işaretçi türü. bunun temel bir yaklaşım olduğuna dikkat edin; numpy dizileri verilerini düz bellekte içermeyebilir, bu nedenle ndarrayınız yapılandırılmışsa, şeklini ve adımlarını dikkate almanız gerekir. Her şey yolundaysa, bu yeterlidir.

+0

+1 atılımlar söz için – Matthias

6

Bunun için bir güncelleştirme: CFFI'nin modern sürümleri ffi.from_buffer() numaralı ffi.from_buffer() numaralı arabelleğe sahiptir. Bu, herhangi bir arabellek nesnesini (numpy dizisi gibi) char * FFI işaretçisine dönüştürür. Artık doğrudan yapabilirsiniz: Doğrudan

cptr = ffi.cast("float *", ffi.from_buffer(my_np_array)) 

veya çağrıya argümanlar (char *float * otomatik döküm edilir) olarak:

C.copy(ffi.from_buffer(arr_in), ffi.from_buffer(arr_out), 16) 
İlgili konular