2012-01-11 9 views
7

मैं पाइथन के लिए सी एक्सटेंशन लिख रहा हूं, जो डेटा पर चलने पर ग्लोबल इंटरप्रेटर लॉक को रिलीज़ करना चाहिए। मुझे लगता है कि मैंने जीआईएल के तंत्र को काफी अच्छी तरह से समझ लिया है, लेकिन एक सवाल बनी हुई है: क्या मैं पाइथन ऑब्जेक्ट में डेटा तक पहुंच सकता हूं जबकि थ्रेड जीआईएल का मालिक नहीं है? उदाहरण के लिए, मैं सी फ़ंक्शन में एक (बड़ी) NumPy सरणी से डेटा पढ़ना चाहता हूं, जबकि मैं अभी भी अन्य थ्रेड को अन्य CPU कोर पर अन्य चीजों को करने की अनुमति देना चाहता हूं। सी समारोह चाहिए अजगर कार्यों ग्लोबल इंटरप्रेटर लॉक और डेटा तक पहुंच (उदाहरण के लिए, NumPy arrays के लिए)

  • का उपयोग कर भी पहले से निर्माण किया NumPy सरणी के लिए डेटा लिखने के बिना

    • रिलीज के साथ Py_BEGIN_ALLOW_THREADS
    • पढ़ने और डेटा पर काम जीआईएल
    • Py_END_ALLOW_THREADS
    साथ जीआईएल पुनः प्राप्त

    क्या यह सुरक्षित है? बेशक, अन्य धागे को वेरिएबल्स को बदलने की आवश्यकता नहीं होती है जो सी फ़ंक्शन का उपयोग करता है। लेकिन शायद त्रुटियों के लिए एक छिपा स्रोत है: क्या पाइथन दुभाषिया एक वस्तु को स्थानांतरित कर सकता है, उदाहरण के लिए। किसी प्रकार के कचरे के संग्रह से, जबकि सी फ़ंक्शन एक अलग धागे में काम करता है?

    कम से कम उदाहरण के साथ प्रश्न को चित्रित करने के लिए, नीचे (न्यूनतम लेकिन पूर्ण) कोड पर विचार करें।

    gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -fPIC -I/usr/lib/pymodules/python2.7/numpy/core/include -I/usr/include/python2.7 -c gilexample.c -o gilexample.o 
    gcc -pthread -shared gilexample.o -o gilexample.so 
    

    साथ (लिनक्स पर) यह संकलन और अजगर पर परीक्षण करना

    import gilexample 
    gilexample.sum([1,2,3]) 
    

    साथ Py_BEGIN_ALLOW_THREADS और Py_END_ALLOW_THREADS सुरक्षित के बीच कोड है? यह एक पायथन ऑब्जेक्ट की सामग्री तक पहुंचता है, और मैं स्मृति में (संभावित रूप से बड़ी) सरणी को डुप्लिकेट नहीं करना चाहता हूं।

    #include <Python.h> 
    #include <numpy/arrayobject.h> 
    
    // The relevant function 
    static PyObject * sum(PyObject * const self, PyObject * const args) { 
        PyObject * X; 
        PyArg_ParseTuple(args, "O", &X); 
        PyObject const * const X_double = PyArray_FROM_OTF(X, NPY_DOUBLE, NPY_ALIGNED); 
        npy_intp const size = PyArray_SIZE(X_double); 
        double * const data = (double *) PyArray_DATA(X_double); 
        double sum = 0; 
    
        Py_BEGIN_ALLOW_THREADS // IS THIS SAFE? 
    
        npy_intp i; 
        for (i=0; i<size; i++) 
        sum += data[i]; 
    
        Py_END_ALLOW_THREADS 
    
        Py_DECREF(X_double); 
        return PyFloat_FromDouble(sum); 
    } 
    
    // Python interface code 
    // List the C methods that this extension provides. 
    static PyMethodDef gilexampleMethods[] = { 
        {"sum", sum, METH_VARARGS}, 
        {NULL, NULL, 0, NULL}  /* Sentinel - marks the end of this structure */ 
    }; 
    
    // Tell Python about these methods. 
    PyMODINIT_FUNC initgilexample(void) { 
        (void) Py_InitModule("gilexample", gilexampleMethods); 
        import_array(); // Must be present for NumPy. 
    } 
    
  • +2

    मैंने अतीत में इस तरह की चीजें की, और मैंने पाया कि यह काम करने का सबसे आसान तरीका आपके सी कार्यों को कॉल करने के लिए 'ctypes' का उपयोग कर रहा है। अपने सी कार्यों को पाइथन या न्यूमपी के संदर्भ के बिना एक शुद्ध सी इंटरफ़ेस दें, और पाइथन में छोटे रैपर लिखें जो NumPy arrays स्वीकार करते हैं और उन्हें उपयुक्त सी पैरामीटर में अनुवाद करते हैं। मैंने [इस उत्तर] में यह कैसे किया है इस पर एक उदाहरण दिया है (http://stackoverflow.com/questions/5862915/passing-numpy-arrays-to-ac-function-for-input-and-output/5868051#5868051)। –

    +0

    @ सेवन: क्या आप जानते हैं कि 'ctypes' मेमोरी में सरणी की एक कार्यशील प्रति बनाता है या नहीं? (1) हां। इस मामले में, मैं इसे नहीं चाहता क्योंकि मैं बड़े इनपुट सरणी से निपट रहा हूं। (2) संख्याफिर मेरा सवाल है कि क्या आप जीआईएल उठा सकते हैं वैध है। हालांकि, मामले में (2), 'ctypes' व्यवहार एक संकेत होगा कि जीआईएल उठाना शायद समस्याग्रस्त नहीं है, कोड में भी जो ctypes का उपयोग नहीं करता है। क्या किसी को पता है कि (1) या (2) धारण करता है? – Daniel

    +5

    नहीं, 'ctypes' सरणी की एक प्रति नहीं बनाता है। और यह आपके लिए जीआईएल जारी करता है, इसलिए आपको इसकी परवाह नहीं है। 'Ctypes' का उपयोग करने का लाभ सादगी है - आपको अभी भी पाइथन में NumPy सरणी से सभी आवश्यक मेटा-जानकारी निकालना है, और जीआईएल को सही समय पर रिलीज़ किया गया है। मैंने इस दृष्टिकोण का उपयोग कई धागे से न्यूमपी सरणी में डेटा तक पहुंचने के लिए किया था। (ध्यान दें कि एक ही मेमोरी में समवर्ती लेखन पहुंच कभी नहीं बचाई जाती है।) –

    उत्तर

    4

    मैं एक अजगर वस्तु में डेटा का उपयोग कर सकते हैं, जबकि धागा जीआईएल का स्वामी नहीं है?

    नहीं, आप नहीं कर सकते।

    +0

    क्या इसका मतलब यह है कि मुझे हमेशा एक NumPy सरणी की सामग्री की प्रतिलिपि बनाना पड़ता है, भले ही मैं केवल थ्रेड में डेटा पढ़ना चाहता हूं? मुझे उम्मीद है कि इसके चारों ओर एक रास्ता है! कोई उपाय? – Daniel

    6

    क्या यह सुरक्षित है?

    कड़ाई से, नहीं। मुझे लगता है कि आपको जीआईएल-कम ब्लॉक के बाहर PyArray_SIZE और PyArray_DATA पर कॉल ले जाना चाहिए; यदि आप ऐसा करते हैं, तो आप केवल सी डेटा पर काम करेंगे। आप जीआईएल-कम ब्लॉक में जाने से पहले ऑब्जेक्ट पर रेफरेंस गिनती भी बढ़ाना चाहते हैं और बाद में इसे घटा सकते हैं।

    आपके संपादन के बाद, यह सुरक्षित होना चाहिए। संदर्भ गणना को बाद में कम करने के लिए मत भूलना।

    +0

    'PyArray_SIZE' और' PyArray_DATA' के बारे में टिप्पणी के लिए धन्यवाद। वह एक ग़लती थी। मैंने अपना प्रश्न संपादित किया और ब्लॉक के बाहर के आदेशों को स्थानांतरित कर दिया जहां जीआईएल जारी किया गया। – Daniel

    +0

    अब: क्या कोड अपने संशोधित संस्करण में सुरक्षित है? क्या आप विस्तृत कर सकते हैं कि संदर्भ गणना में वृद्धि क्यों चीजों को बदल देगी? – Daniel

    +0

    @Daniel: संदर्भ गणना की आवश्यकता हो सकती है (हालांकि मुझे इस मामले में पूरी तरह से यकीन नहीं है) क्योंकि कोई अन्य थ्रेड सरणी को रद्द नहीं करना चाहिए। –

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