2013-03-04 4 views
8

मैंने हाल ही में PyPy को आजमाया और दृष्टिकोण से चिंतित था। मेरे पास पाइथन के लिए बहुत से सी एक्सटेंशन हैं, जो सभी सरणी के डेटा अनुभागों में पॉइंटर प्राप्त करने के लिए PyArray_DATA() का उपयोग करते हैं। दुर्भाग्यवश, पीपीपी cpyext मॉड्यूल में उनके numpypy सरणी के बराबर निर्यात करने के लिए प्रतीत नहीं होता है, इसलिए मैंने ctypes का उपयोग करने के लिए अपनी वेबसाइट पर अनुशंसा का पालन करने का प्रयास किया। यह पायथन स्तर पर पॉइंटर प्राप्त करने का कार्य धक्का देता है।Numpy/Numpypy डेटा को पॉइंटर प्राप्त करने के लिए पोर्टेबल/तेज़ तरीका

import ctypes as C 
p_t = C.POINTER(C.c_double) 

def get_ptr_ctypes(x): 
    return x.ctypes.data_as(p_t) 

def get_ptr_array(x): 
    return C.cast(x.__array_interface__['data'][0], p_t) 

केवल दूसरा एक PyPy पर काम करता है, इसलिए संगतता के लिए चुनाव स्पष्ट है:

दो तरीके दिखाई देते हैं। सीपीथॉन के लिए, दोनों नरक के रूप में धीमे हैं और मेरे आवेदन के लिए एक पूर्ण बाधा है! क्या इस सूचक को प्राप्त करने का एक तेज़ और पोर्टेबल तरीका है? या पीपीपी (संभवतः अनियंत्रित) के लिए PyArray_DATA() के बराबर है?

उत्तर

4

मैं अभी भी एक पूरी तरह से संतोषजनक समाधान नहीं मिला है, लेकिन फिर भी वहाँ कुछ है कोई सीपीथॉन में बहुत कम ओवरहेड के साथ पॉइंटर प्राप्त करने के लिए कर सकता है। सबसे पहले, कारण बताए गए दोनों तरीकों इतनी धीमी हैं कि .ctypes और .__array_interface__ ऑन-डिमांड विशेषताओं हैं, जो array_ctypes_get() और array_interface_get()numpy/numpy/core/src/multiarray/getset.c में सेट हैं। पहला आयात ctypes और numpy.core._internal._ctypes उदाहरण बनाता है, जबकि दूसरा एक नया शब्दकोश बनाता है और डेटा पॉइंटर के अलावा बहुत सारी अनावश्यक सामग्री के साथ इसे पॉप्युलेट करता है।

कुछ भी नहीं इस भूमि के ऊपर के बारे में अजगर स्तर पर कर सकते हैं नहीं है, लेकिन एक सी-स्तर पर एक माइक्रो मॉड्यूल है कि भूमि के ऊपर से ज्यादातर को नजरअंदाज लिख सकते हैं: हमेशा की तरह

#include <Python.h> 
#include <numpy/arrayobject.h> 

PyObject *_get_ptr(PyObject *self, PyObject *obj) { 
    return PyLong_FromVoidPtr(PyArray_DATA(obj)); 
} 

static PyMethodDef methods[] = { 
    {"_get_ptr", _get_ptr, METH_O, "Wrapper to PyArray_DATA()"}, 
    {NULL, NULL, 0, NULL} 
}; 

PyMODINIT_FUNC initaccel(void) { 
    Py_InitModule("accel", methods); 
} 

संकलित एक के रूप में setup.py में एक्सटेंशन, और आयात

try: 
    from accel import _get_ptr 
    def get_ptr(x): 
     return C.cast(_get_ptr(x), p_t) 
except ImportError: 
    get_ptr = get_ptr_array 

PyPy पर, के रूप में from accel import _get_ptr असफल हो जायेगी और get_ptr वापस get_ptr_array तक कम हो जाएगा, जो Numpypy साथ काम करता है।

जहां तक ​​प्रदर्शन चलता है, हल्के वजन सी फ़ंक्शन कॉल के लिए, ctypes + accel._get_ptr() देशी सीपीथन एक्सटेंशन की तुलना में काफी धीमी है, जो अनिवार्य रूप से कोई ओवरहेड नहीं है। यह get_ptr_ctypes() और get_ptr_array() से अधिक तेज़ है, ताकि ओवरहेड मध्यम-वजन सी फ़ंक्शन कॉल के लिए महत्वहीन हो सके।

किसी ने पीपीपी के साथ संगतता प्राप्त की है, हालांकि मुझे यह कहना है कि मेरे वैज्ञानिक गणना अनुप्रयोगों के लिए पीईपीई का मूल्यांकन करने की कोशिश करने में काफी समय व्यतीत करने के बाद, मुझे इसके लिए भविष्य नहीं दिखता है जब तक कि वे (काफी हद तक जिद्दी) पूर्ण सीपीथन एपीआई का समर्थन करने से इंकार कर दिया।

अद्यतन

मैंने पाया कि ctypes.cast() अब accel._get_ptr() पेश करने के बाद टोंटी होता जा रहा था। इंटरफ़ेस में सभी पॉइंटर्स को ctypes.c_void_p के रूप में घोषित करके जानवरों से छुटकारा पा सकता है।

def get_ptr_ctypes2(x): 
    return x.ctypes._data 

def get_ptr_array(x): 
    return x.__array_interface__['data'][0] 

try: 
    from accel import _get_ptr as get_ptr 
except ImportError: 
    get_ptr = get_ptr_array 

यहाँ, get_ptr_ctypes2() छिपा ndarray.ctypes._data विशेषता सीधे पहुंच कर डाली से बचा जाता है: यह है कि मैं क्या साथ समाप्त हो गया है। यहाँ अजगर से भारी वजन और हल्के वजन सी कार्यों फोन करने के लिए कुछ समय परिणाम हैं:

       heavy C (few calls)  light C (many calls) 
ctypes + get_ptr_ctypes():   0.71 s     15.40 s 
ctypes + get_ptr_ctypes2():  0.68 s     13.30 s 
ctypes + get_ptr_array():   0.65 s     11.50 s 
ctypes + accel._get_ptr():   0.63 s     9.47 s 

native CPython:     0.62 s     8.54 s 
Cython (no decorators):   0.64 s     9.96 s 

तो, accel._get_ptr() साथ और कोई ctypes.cast() रों, ctypes 'गति वास्तव में एक देशी CPython विस्तार के साथ प्रतिस्पर्धी है। तो मैं बस जब तक किसी को h5py, matplotlib और scipy पुनर्लेखन ctypes के साथ कुछ भी गंभीर के लिए PyPy कोशिश करने के लिए सक्षम होने के लिए इंतजार करना पड़ता है ...

0

शायद यह पर्याप्त उत्तर नहीं दे सकता है, लेकिन उम्मीद है कि एक अच्छा संकेत है। मैं अपने कोड के कुछ हिस्सों में scipy.weave.inline() का उपयोग कर रहा हूं। मैं इंटरफ़ेस की गति के बारे में बहुत कुछ नहीं जानता, क्योंकि मेरे द्वारा निष्पादित कार्य काफी भारी है और केवल कुछ पॉइंटर्स/सरणी पर निर्भर करता है, लेकिन यह मेरे लिए तेज़ लगता है। शायद तुम, विशेष रूप से attempt_function_call

https://github.com/scipy/scipy/blob/master/scipy/weave/inline_tools.py#L390

आप सी ++ कोड कि scipy.weave द्वारा उत्पन्न होता है पर एक नजर है चाहते हैं से, scipy.weave कोड से कुछ प्रेरणा प्राप्त कर सकते हैं

  1. यहां से एक सरल उदाहरण का उत्पादन: http://docs.scipy.org/doc/scipy/reference/tutorial/weave.html,

  2. रन अजगर स्क्रिप्ट

  3. scipy.weave कैश फ़ोल्डर मिलती है:

    import scipy.weave.catalog as ctl 
    ctl.default_dir() 
    Out[5]: '/home/user/.python27_compiled' 
    
  4. फ़ोल्डर में उत्पन्न सी ++ कोड पर एक नजर है
+0

दुर्भाग्य से, 'scipy.weave' सी कोड CPython एपीआई का उपयोग कर के उत्पादन की तुलना और कुछ नहीं (करता है '# शामिल करें '), जो 'पीपीपी' के साथ काम नहीं करेगा। सीपीथॉन एपीआई के भीतर, 'PyArray_DATA() 'numpy arrays के डेटा सेक्शन में पॉइंटर प्राप्त करने का सबसे प्रभावी तरीका है, लेकिन यह PyPy के लिए पोर्टेबल नहीं है। – Stefan

संबंधित मुद्दे