(साथ NxM 1K < = एन < = 20K & 10K < = एम < = 200K), मैं अक्सर Numpy पास करनी होगी नौकरी पाने के लिए साइथन के माध्यम से सी ++ के लिए matrices और यह प्रतिलिपि के बिना & अपेक्षित के रूप में काम करता है।नकल के बिना Cython के माध्यम से Numpy को पासिंग सी ++ वेक्टर और बड़े मैट्रिक्स प्रसंस्करण के साथ काम स्वचालित रूप से स्मृति प्रबंधन की देखभाल
हालांकि, कई बार जब मैं शुरू करने और C++ एक मैट्रिक्स preprocess और यह Numpy (अजगर 3.6) को पास किए जाने हैं। आइए मान लें कि मैट्रिस रैखिकृत हैं (इसलिए आकार एन * एम है और यह 1 डी मैट्रिक्स है - कॉल/पंक्ति प्रमुख यहां कोई फर्क नहीं पड़ता)। यहां दी गई जानकारी के बाद: exposing C-computed arrays in Python without data copies & इसे C++ संगतता के लिए संशोधित करने के लिए, मैं सी ++ सरणी पास करने में सक्षम हूं।
समस्या है यदि मैं सरणी शुरू करने के बजाय std वेक्टर का उपयोग करना चाहता हूं, तो मुझे सेगमेंटेशन गलती मिल जाएगी। उदाहरण के लिए, निम्न फ़ाइलों पर विचार:
fast.h
#include <iostream>
#include <vector>
using std::cout; using std::endl; using std::vector;
int* doit(int length);
fast.cpp
#include "fast.h"
int* doit(int length) {
// Something really heavy
cout << "C++: doing it fast " << endl;
vector<int> WhyNot;
// Heavy stuff - like reading a big file and preprocessing it
for(int i=0; i<length; ++i)
WhyNot.push_back(i); // heavy stuff
cout << "C++: did it really fast" << endl;
return &WhyNot[0]; // or WhyNot.data()
}
faster.pyx
cimport numpy as np
import numpy as np
from libc.stdlib cimport free
from cpython cimport PyObject, Py_INCREF
np.import_array()
cdef extern from "fast.h":
int* doit(int length)
cdef class ArrayWrapper:
cdef void* data_ptr
cdef int size
cdef set_data(self, int size, void* data_ptr):
self.data_ptr = data_ptr
self.size = size
def __array__(self):
print ("Cython: __array__ called")
cdef np.npy_intp shape[1]
shape[0] = <np.npy_intp> self.size
ndarray = np.PyArray_SimpleNewFromData(1, shape,
np.NPY_INT, self.data_ptr)
print ("Cython: __array__ done")
return ndarray
def __dealloc__(self):
print("Cython: __dealloc__ called")
free(<void*>self.data_ptr)
print("Cython: __dealloc__ done")
def faster(length):
print("Cython: calling C++ function to do it")
cdef int *array = doit(length)
print("Cython: back from C++")
cdef np.ndarray ndarray
array_wrapper = ArrayWrapper()
array_wrapper.set_data(length, <void*> array)
print("Ctyhon: array wrapper set")
ndarray = np.array(array_wrapper, copy=False)
ndarray.base = <PyObject*> array_wrapper
Py_INCREF(array_wrapper)
print("Cython: all done - returning")
return ndarray
setup.py
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
import numpy
ext_modules = [Extension(
"faster",
["faster.pyx", "fast.cpp"],
language='c++',
extra_compile_args=["-std=c++11"],
extra_link_args=["-std=c++11"]
)]
setup(
cmdclass = {'build_ext': build_ext},
ext_modules = ext_modules,
include_dirs=[numpy.get_include()]
)
आप
python setup.py build_ext --inplace
के साथ इस का निर्माण और अजगर 3.6 दुभाषिया चलाने के लिए, यदि आप में प्रवेश करता है, तो निम्नलिखित आप SEG मिलता था की कोशिश करता की एक जोड़ी के बाद गलती।
>>> from faster import faster
>>> a = faster(1000000)
Cython: calling C++ function to do it
C++: doing it fast
C++: did it really fast
Cython: back from C++
Ctyhon: array wrapper set
Cython: __array__ called
Cython: __array__ done
Cython: all done - returning
>>> a = faster(1000000)
Cython: calling C++ function to do it
C++: doing it fast
C++: did it really fast
Cython: back from C++
Ctyhon: array wrapper set
Cython: __array__ called
Cython: __array__ done
Cython: all done - returning
Cython: __dealloc__ called
Segmentation fault (core dumped)
चीजों की युगल गौर करने योग्य
- आप सरणी (fast.cpp में) वेक्टर के बजाय का उपयोग करते हैं यह एक आकर्षण की तरह काम करेगा!
- यदि आप
faster(1000000)
पर कॉल करते हैं और परिणामvariable a
के अलावा किसी अन्य चीज़ में डालते हैं तो यह काम करेगा।
आप दर्ज करते हैं faster(10)
की तरह छोटी संख्या आप की तरह एक अधिक विस्तृत जानकारी प्राप्त करेंगे:
Cython: calling C++ function to do it
C++: doing it fast
C++: did it really fast
Cython: back from C++
Ctyhon: array wrapper set
Cython: __array__ called
Cython: __array__ done
Cython: all done - returning
Cython: __dealloc__ called <--- Perhaps this happened too early or late?
*** Error in 'python': double free or corruption (fasttop): 0x0000000001365570 ***
======= Backtrace: =========
More info here ....
यह वास्तव में puzzling है यही कारण है कि इस सरणियों के साथ ऐसा नहीं होता है? कोई बात नहीं क्या!
मैं वैक्टरों का बहुत उपयोग करता हूं और इन परिदृश्यों में उनका उपयोग करने में सक्षम होना पसंद करूंगा।
@AndyG जब आपको लगता है यह हो रहा है करते हैं? जब 'काम' समारोह दूसरी बार बुलाया जाता है? क्या वह एक नया वेक्टर शुरू नहीं करेगा? या यह मूल रूप से पहले भरे वेक्टर का आकार बदल रहा है? यदि हां, तो क्यों? – NULL
मुझे खेद से पहले वास्तव में आपके कोड को नहीं देखा था। आपके कोड में व्यवहार को अपरिभाषित किया गया है क्योंकि यह अस्थायी संदर्भ को वापस कर रहा है। 'Doit' के बाद वेक्टर गुंजाइश से बाहर चला जाता है। आपके पास सरणी के साथ एक ही समस्या होगी (मैं यहां 'std :: array' मान रहा हूं)। आपको एक सेगमेंटेशन गलती मिलती है, आप अपने आशीर्वादों को गिन सकते हैं, क्योंकि यह चुपचाप आपको कचरा दे सकता है। गतिशील रूप से आवंटित सरणी (सी-शैली सरणी) के साथ आपको यह समस्या नहीं होगी क्योंकि स्मृति को हटाया नहीं जा रहा है। मुझे लगता है कि आप मेमोरी को साइथन के पास ले जा सकते हैं, फिर? अन्यथा आपको मेमोरी लीक – AndyG
@ एंडीजी देखेंगे, हाँ, जो समझ में आता है। जैसा कि मैंने उल्लेख किया है गतिशील सरणी (सी-शैली सरणी) ठीक काम करते हैं। क्या वैसे भी है कि मैं वापसी के लिए वेक्टर को सरणी में कॉपी करने से बच सकता हूं? – NULL