मेरे पास एक सी फ़ंक्शन है जो mallocs() और फ्लोट की 2 डी सरणी पॉप्युलेट करता है। यह पता और सरणी के आकार "रिटर्न" देता है। हस्ताक्षरक्या मैं अपनी स्मृति के स्वामित्व को लेने के लिए एक numpy ndarray को मजबूर कर सकता हूं?
int get_array_c(float** addr, int* nrows, int* ncols);
मैं इसे अजगर से कॉल करना चाहते है, इसलिए मैं ctypes का उपयोग करें।
import ctypes
mylib = ctypes.cdll.LoadLibrary('mylib.so')
get_array_c = mylib.get_array_c
मैं कभी नहीं पता चल ctypes के साथ तर्क प्रकार निर्दिष्ट करने के लिए कैसे। मैं केवल प्रत्येक सी फ़ंक्शन के लिए एक पायथन रैपर लिखता हूं, और सुनिश्चित करता हूं कि मुझे रैपर में सही प्रकार मिलते हैं। फ्लोट्स की सरणी स्तंभ-प्रमुख क्रम में एक मैट्रिक्स है, और मैं इसे numpy.ndarray के रूप में प्राप्त करना चाहता हूं। लेकिन यह बहुत बड़ा है, इसलिए मैं सी फंक्शन द्वारा आवंटित स्मृति का उपयोग करना चाहता हूं, इसकी प्रतिलिपि नहीं बनाऊंगा। (मैं तो बस इस StackOverflow जवाब में इस PyBuffer_FromMemory सामान मिला: https://stackoverflow.com/a/4355701/3691)
buffer_from_memory = ctypes.pythonapi.PyBuffer_FromMemory
buffer_from_memory.restype = ctypes.py_object
import numpy
def get_array_py():
nrows = ctypes.c_int()
ncols = ctypes.c_int()
addr_ptr = ctypes.POINTER(ctypes.c_float)()
get_array_c(ctypes.byref(addr_ptr), ctypes.byref(nrows), ctypes.byref(ncols))
buf = buffer_from_memory(addr_ptr, 4 * nrows * ncols)
return numpy.ndarray((nrows, ncols), dtype=numpy.float32, order='F',
buffer=buf)
यह मैं सही मूल्यों के साथ एक सरणी देने के लिए लगता है। लेकिन मुझे यकीन है कि यह एक स्मृति रिसाव है।
>>> a = get_array_py()
>>> a.flags.owndata
False
सरणी में स्मृति का स्वामित्व नहीं है। काफी उचित; डिफ़ॉल्ट रूप से, जब सरणी एक बफर से बनाई जाती है, तो यह नहीं होना चाहिए। लेकिन इस मामले में यह चाहिए। जब numpy सरणी हटा दी जाती है, तो मुझे वास्तव में मेरे लिए बफर मेमोरी मुक्त करने के लिए पायथन पसंद है। ऐसा लगता है जैसे मैं ओवांडाटा को सच में मजबूर कर सकता हूं, इसे करना चाहिए, लेकिन ओवंडाटा सेटटेबल नहीं है।
असंतोषजनक समाधान:
get_array_py के फोन करने वाले() स्मृति को मुक्त कराने के लिए जिम्मेदार बनाओ। यह बहुत परेशान है; कॉलर किसी भी अन्य numpy सरणी की तरह इस numpy सरणी का इलाज करने में सक्षम होना चाहिए।
मूल सरणी को get_array_py में एक नई numpy सरणी (अपनी खुद की, अलग स्मृति के साथ) में कॉपी करें, पहले सरणी को हटाएं, और get_array_py() के अंदर मेमोरी को मुक्त करें। मूल सरणी के बजाय प्रतिलिपि वापस करें। यह कष्टप्रद है क्योंकि यह अनावश्यक स्मृति प्रतिलिपि होना चाहिए।
क्या मैं चाहता हूं कि ऐसा करने का कोई तरीका है? मैं सी फ़ंक्शन को स्वयं संशोधित नहीं कर सकता, हालांकि यदि यह सहायक है तो मैं लाइब्रेरी में एक और सी फ़ंक्शन जोड़ सकता हूं।
यह दर्द की दुनिया की तरह लगता है .. मुझे लगता है कि आप [segfault hell] (http://xkcd.com/371/) – wim
के लिए पूछ रहे हैं मैंने सीटीपीएस का उपयोग करके सफलता के बिना भी कोशिश की है। एक पूर्ण अप एक्सटेंशन मॉड्यूल यह संभव बनाता है लेकिन वे लिखने के लिए और अधिक काम करते हैं। –