खोज…


एक DLL रैपिंग: C ++ से साइथन को पायथन

यह साइथन के साथ C ++ dll को लपेटने का एक गैर-तुच्छ उदाहरण प्रदर्शित करता है। यह निम्नलिखित मुख्य चरणों को कवर करेगा:

  • Visual Studio का उपयोग करके C ++ के साथ एक उदाहरण DLL बनाएं।
  • साइथन के साथ DLL लपेटें ताकि इसे पायथन में बुलाया जा सके।

यह माना जाता है कि आपके पास साइथन स्थापित है और इसे सफलतापूर्वक पायथन में आयात कर सकते हैं।

DLL चरण के लिए, यह भी माना जाता है कि आप Visual Studio में DLL बनाने से परिचित हैं।

पूर्ण उदाहरण में निम्न फ़ाइलों का निर्माण शामिल है:

  1. complexFunLib.h : C ++ DLL स्रोत के लिए हैडर फ़ाइल
  2. complexFunLib.cpp : C ++ DLL स्रोत के लिए CPP फ़ाइल
  3. ccomplexFunLib.pxd : ccomplexFunLib.pxd "हेडर" फ़ाइल
  4. complexFunLib.pyx : Cython "आवरण" फ़ाइल
  5. setup.py : Python setup file for complexFunLib.pyd को complexFunLib.pyd साथ बनाने के लिए
  6. run.py : उदाहरण Python फ़ाइल जो संकलित आयात करता है, Cython लिपटे DLL

सी ++ डीएलएल स्रोत: complexFunLib.h और complexFunLib.cpp

यदि आपके पास पहले से ही DLL और हैडर स्रोत फ़ाइल है, तो इसे छोड़ दें। सबसे पहले, हम C ++ स्रोत बनाते हैं जिसमें से Visual Studio का उपयोग करके DLL संकलित किया जाएगा। इस मामले में, हम जटिल घातीय फ़ंक्शन के साथ तेज़ सरणी गणना करना चाहते हैं। निम्नलिखित दो कार्य सरणियों k और ee पर गणना k*exp(ee) करते हैं, जहां परिणाम res में संग्रहीत किए जाते हैं। सिंगल और डबल प्रिसिजन दोनों को समायोजित करने के लिए दो कार्य हैं। ध्यान दें कि ये उदाहरण फ़ंक्शन OpenMP का उपयोग करते हैं, इसलिए सुनिश्चित करें कि OpenMP प्रोजेक्ट के लिए Visual Studio विकल्पों में सक्षम है।

ज फाइल

// Avoids C++ name mangling with extern "C"
#define EXTERN_DLL_EXPORT extern "C" __declspec(dllexport)  
#include <complex>
#include <stdlib.h>

// Handles 64 bit complex numbers, i.e. two 32 bit (4 byte) floating point numbers
EXTERN_DLL_EXPORT void mp_mlt_exp_c4(std::complex<float>* k, 
                                     std::complex<float>* ee,
                                     int sz, 
                                     std::complex<float>* res, 
                                     int threads);

// Handles 128 bit complex numbers, i.e. two 64 bit (8 byte) floating point numbers
EXTERN_DLL_EXPORT void mp_mlt_exp_c8(std::complex<double>* k,                                       std::complex<double>* ee,
                                     int sz, 
                                     std::complex<double>* res, 
                                     int threads);

CPP फ़ाइल

#include "stdafx.h"
#include <stdio.h>
#include <omp.h>
#include "complexFunLib.h"

void mp_mlt_exp_c4(std::complex<float>* k,
                   std::complex<float>* ee,
                   int sz,
                   std::complex<float>* res,
                   int threads)
{
    // Use Open MP parallel directive for multiprocessing
    #pragma omp parallel num_threads(threads)
    {
        #pragma omp for
        for (int i = 0; i < sz; i++) res[i] = k[i] * exp(ee[i]);
    }
}

void mp_mlt_exp_c8(std::complex<double>* k,
                   std::complex<double>* ee,
                   int sz, std::complex<double>* res,
                   int threads)
{
    // Use Open MP parallel directive for multiprocessing
    #pragma omp parallel num_threads(threads)
    {
        #pragma omp for
        for (int i = 0; i < sz; i++) res[i] = k[i] * exp(ee[i]);
    }
}

ccomplexFunLib.pxd स्रोत: ccomplexFunLib.pxd और complexFunLib.pyx

अगला, हम C ++ DLL को लपेटने के लिए आवश्यक Cython स्रोत फ़ाइलें बनाते हैं। इस चरण में, हम निम्नलिखित धारणाएँ बनाते हैं:

  • आपने साइथन को स्थापित किया है
  • आपके पास एक काम करने वाला DLL है, जैसे ऊपर वर्णित एक

अंतिम लक्ष्य एक .pyd फ़ाइल को संकलित करने के लिए मूल DLL के साथ संयोजन में इन Cython स्रोत फ़ाइलों का उपयोग करना है, जिसे पायथन मॉड्यूल के रूप में आयात किया जा सकता है और C ++ में लिखे गए कार्यों को उजागर करता है।

पीएक्सडी फ़ाइल

यह फ़ाइल C ++ हैडर फ़ाइल से मेल खाती है। ज्यादातर मामलों में, आप इस फ़ाइल पर हेडर को मामूली साइथन विशिष्ट परिवर्तनों के साथ कॉपी-पेस्ट कर सकते हैं। इस मामले में, विशिष्ट साइथन जटिल प्रकार का उपयोग किया गया था। ccomplexFunLib.pxd की शुरुआत में c के जोड़ पर ध्यान दें। यह आवश्यक नहीं है, लेकिन हमने पाया है कि इस तरह के नामकरण सम्मेलन से संगठन को बनाए रखने में मदद मिलती है।

cdef extern from "complexFunLib.h":
    void mp_mlt_exp_c4(float complex* k, float complex* ee, int sz,
                       float complex* res, int threads);
    void mp_mlt_exp_c8(double complex* k, double complex* ee, int sz,
                       double complex* res, int threads);

PYX फ़ाइल

यह फ़ाइल C ++ cpp स्रोत फ़ाइल से मेल खाती है। इस उदाहरण में, हम Numpy ndarray ऑब्जेक्ट्स को DLL फ़ंक्शंस आयात करने के लिए पॉइंटर्स पास करेंगे। यह भी Cython में बनाया उपयोग करना संभव है memoryview सरणियों के लिए वस्तु, लेकिन जैसा कि इसके प्रदर्शन को अच्छा के रूप में नहीं किया जा सकता ndarray वस्तुओं (हालांकि वाक्य रचना काफी क्लीनर है)।

cimport ccomplexFunLib  # Import the pxd "header"
# Note for Numpy imports, the C import most come AFTER the Python import
import numpy as np  # Import the Python Numpy
cimport numpy as np  # Import the C Numpy

# Import some functionality from Python and the C stdlib
from cpython.pycapsule cimport *

# Python wrapper functions.
# Note that types can be delcared in the signature

def mp_exp_c4(np.ndarray[np.complex64_t, ndim=1] k,
              np.ndarray[np.complex64_t, ndim=1] ee,
              int sz,
              np.ndarray[np.complex64_t, ndim=1] res,
              int threads):
    '''
    TODO: Python docstring
    '''
    # Call the imported DLL functions on the parameters.
    # Notice that we are passing a pointer to the first element in each array
    ccomplexFunLib.mp_mlt_exp_c4(&k[0], &ee[0], sz, &res[0], threads)
    
def mp_exp_c8(np.ndarray[np.complex128_t, ndim=1] k,
              np.ndarray[np.complex128_t, ndim=1] ee,
              int sz,
              np.ndarray[np.complex128_t, ndim=1] res,
              int threads):
    '''
    TODO: Python docstring
    '''
    ccomplexFunLib.mp_mlt_exp_c8(&k[0], &ee[0], sz, &res[0], threads)

पायथन स्रोत: setup.py और run.py

setup.py

यह फ़ाइल पायथन फ़ाइल है जो साइथन संकलन को निष्पादित करती है। इसका उद्देश्य संकलित .pyd फ़ाइल को उत्पन्न करना है जिसे तब पायथन मॉड्यूल द्वारा आयात किया जा सकता है। इस उदाहरण में, हमने सभी आवश्यक फाइलें (जैसे complexFunLib.h , complexFunLib.dll , ccomplexFunLib.pxd , और complexFunLib.pyx ) को उसी निर्देशिका में setup.py रूप में रखा है।

एक बार जब यह फ़ाइल बन जाती है, तो इसे कमांड लाइन से मापदंडों के साथ चलाया जाना चाहिए: build_ext --inplace

एक बार जब यह फ़ाइल निष्पादित हो जाती है, तो इसे बिना किसी त्रुटि के एक .pyd फ़ाइल का उत्पादन करना चाहिए। ध्यान दें कि कुछ मामलों में अगर कोई गलती है .pyd बनाया जा सकता है लेकिन अमान्य है। सुनिश्चित करें कि उत्पन्न .pyd का उपयोग करने से पहले setup.py के निष्पादन में कोई त्रुटि नहीं .pyd

from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
import numpy as np

ext_modules = [
    Extension('complexFunLib',
              ['complexFunLib.pyx'],
              # Note here that the C++ language was specified
              # The default language is C
              language="c++",  
              libraries=['complexFunLib'],
              library_dirs=['.'])
    ]

setup(
    name = 'complexFunLib',
    cmdclass = {'build_ext': build_ext},
    ext_modules = ext_modules,
    include_dirs=[np.get_include()]  # This gets all the required Numpy core files
)

run.py

अब complexFunLib को सीधे पायथन मॉड्यूल और लिपटे DLL फ़ंक्शन में आयात किया जा सकता है।

import complexFunLib
import numpy as np

# Create arrays of non-trivial complex numbers to be exponentiated,
# i.e. res = k*exp(ee)
k = np.ones(int(2.5e5), dtype='complex64')*1.1234 + np.complex64(1.1234j)
ee = np.ones(int(2.5e5), dtype='complex64')*1.1234 + np.complex64(1.1234j) 
sz = k.size  # Get size integer
res = np.zeros(int(2.5e5), dtype='complex64')  # Create array for results

# Call function
complexFunLib.mp_exp_c4(k, ee, sz, res, 8)  

# Print results
print(res)


Modified text is an extract of the original Stack Overflow Documentation
के तहत लाइसेंस प्राप्त है CC BY-SA 3.0
से संबद्ध नहीं है Stack Overflow