美文网首页程序员软件测试Python专家之路工具癖
python高性能扩展工具-cython教程2基础

python高性能扩展工具-cython教程2基础

作者: python测试开发 | 来源:发表于2018-09-21 06:03 被阅读54次

    本章涉及的主要内容:

    • 链接模型
    • Cython关键字 - cdef
    • Typedef和函数指针
    • public关键字
    • 关键字cpdef
    • C/C+++调用Python logging
    • C/C++用Python ConfigParser
    • Python到C/C++的回调
    • Cython PXD
    • 与构建系统集成

    链接模型

    C/C++中嵌入python

    image.png

    cython模式

    image.png

    cdef

    cdef关键字告诉编译器该语句是本地C类型或本地函数。比如:

    cdef int AddFunction(int, int)
    
    def square(int x):
        return x ** 2
    

    Struct

    C的struct 可以直接在Cython中使用。比如mycode.h

    
    #ifndef __MYCODE_H__
    #define __MYCODE_H__
    
    struct mystruct {
      char * string;
      int integer;
      char ** string_array;
    };
    
    extern void printStruct (struct mystruct *);
    
    #endif //__MYCODE_H__
    
    

    printStruct函数的实现 mycode.c

    #include <stdio.h>
    #include "mycode.h"
    
    void printStruct (struct mystruct * s)
    {
      printf (".string = %s\n", s->string);
      printf (".integer = %i\n", s->integer);
      printf (".string_array = \n");
    
      int i;
      for (i = 0; i < s->integer; ++i)
        printf ("\t[%i] = %s\n", i, s->string_array [i]);
    }
    

    Python导入调用:mycodepy.pyx

    cdef extern from "mycode.h":
      struct mystruct:
        char * string
        int integer
        char ** string_array
      void printStruct (mystruct *)
    
    def testStruct ():
        cdef mystruct s
        cdef char *array [2]
        s.string = "Hello World"
        s.integer = 2
        array [0] = "foo"
        array [1] = "bar"
        s.string_array = array
        printStruct (&s)
    
    

    嵌套结构体void myfunc (struct mystruct * x)在cython的定义:void myfunc (mystruct * x)。cython中没有→操作符号,要使用点号。

    执行

    $ make
    cython -3 -o mycodepy.c mycodepy.pyx
    gcc -g -O2 -fpic -c mycodepy.c -o mycodepy.o `python3-config --cflags`
    gcc -g -O2 -fpic -c mycode.c -o mycode.o
    gcc -g -O2 -shared -o mycodepy.so mycode.o mycodepy.o
    $ python
    Python 3.6.5 |Anaconda, Inc.| (default, Apr 29 2018, 16:14:56) 
    [GCC 7.2.0] on linux
    Type "help", "copyright", "credits" or "license" for more information.
    >>> from mycodepy import testStruct
    >>> from mycodepy import testStruct
    >>> testStruct ()
    .string = Hello World
    .integer = 2
    .string_array = 
        [0] = foo
        [1] = bar
    

    Enum

    c中的实现:

    
    enum cardsuit {
        CLUBS,
        DIAMONDS,
        HEARTS,
        SPADES
    };
    

    Cython定义

    
    cdef enum cardsuit:
        CLUBS, DIAMONDS, HEARTS, SPADES
    
    # 使用
    cdef cardsuit card = CLUBS
    

    Typedef和函数指针

    c中的实现:

    
    struct foobar {
        int x;
        char * y;
    };
    
    typedef struct foobar foobar_t;
    typedef void (*cfptr) (int)
    

    Cython定义

    
    cdef struct foobar:
        int x
        char * y
    ctypedef foobar foobar_t
    
    # 使用
    ctypedef int * int_ptr
    ctypedef void (*cfptr)(int
    cdef cfptr myfunctionptr = &myfunc
    

    Typedef和函数指针

    这是Cython中非常强大的关键字。 它允许任何带有public修饰符的cdef声明输出相应的C/C++头,其中相关声明可从C/C++访问。 例如,我们可以声明:

    
    cdef public struct CythonStruct:
        size_t number_of_elements;
        char ** elements;
    

    编译后会生成cython_input.h

    
    struct CythonStruct {
        size_t number_of_elements;
        char ** elements;
    };
    

    c调用要求在嵌入libpython.so,并执行初始化:

    #include <Python.h>
    
    int main(int argc, char **argv) {
        Py_Initialize ();
        // code in here
        Py_Finalize ();
        return 0;
    }
    

    调用前需要初始化cythonfile.pyx(如果有)的

    cdef public void cythonFunction ():
        print "inside cython function!!!"
    

    这样会生成cythonfile.c和cythonfile.h。

    /* Boiler plate init Python */
    Py_SetProgramName (argv [0]);
    Py_Initialize ();
    /* Init our config module into Python memory */
    initpublicTest ();
    cythonFunction ();
    /* cleanup python before exit... */
    Py_Finalize ();
    

    这个步骤类似python中的import cythonfile

    cpdef

    函数声明def在python和cython中可调用,cdef在c系列可以调用,cpdef在两者都可以调用,但是返回要知道类型,且丧失了cython的类型安全,不推荐这么做。

    long returnValue = PyInt_AsLong (test (1, 0))

    实例:C/C++调用python logging

    main.c

    #include "NativeLogging.h"
    
    int main(int argc, char **argv)
    {
        // we want to ensure we use a command line argument for the output log file
        if (argc < 2) {
            return -1;
        }
    
        // use the first argument as log file
        SetupNativeLogging(argv[1]);
    
        // log out some stuff at different levels
        info("info message");
        debug("debug message");
        error("error message");
    
        // close up everything including Python
        CloseNativeLogging();
    
        return 0;
    }
    
    

    NativeLogging.h

    #ifndef __NATIVE_LOGGING_H__
    #define __NATIVE_LOGGING_H__
    
    #define printflike __attribute__ ((format (printf, 3, 4)))
    
    extern void printflike native_logging_info(const char *, unsigned, const char *, ...);
    extern void printflike native_logging_debug(const char *, unsigned, const char *, ...);
    extern void printflike native_logging_error(const char *, unsigned, const char *, ...);
    
    #define info(...)  native_logging_info(__FILE__, __LINE__, __VA_ARGS__)
    #define error(...) native_logging_debug(__FILE__, __LINE__, __VA_ARGS__)
    #define debug(...) native_logging_error(__FILE__, __LINE__, __VA_ARGS__)
    
    extern void SetupNativeLogging(const char * logFileName);
    extern void CloseNativeLogging();
    
    #endif // __NATIVE_LOGGING_H__
    
    

    NativeLogging.c

    #include <Python.h>
    #include <stdio.h>
    #include <stdarg.h>
    
    #include "PythonLoggingBackend.h"
    #include "NativeLogging.h"
    
    void native_logging_info(const char * file, unsigned line, const char * fmt, ...)
    {
        char buffer[256];
        va_list args;
        va_start(args, fmt);
        vsprintf(buffer, fmt, args);
        va_end(args);
    
        char buf[512];
        snprintf(buf, sizeof(buf), "%s:%i -> %s", file, line, buffer);
        python_info(buf);
    }
    
    void native_logging_debug(const char * file, unsigned line,const char * fmt, ...)
    {
        char buffer[256];
        va_list args;
        va_start(args, fmt);
        vsprintf(buffer, fmt, args);
        va_end(args);
    
        char buf[512];
        snprintf(buf, sizeof(buf), "%s-%i -> %s", file, line, buffer);
        python_debug(buf);
    }
    
    void native_logging_error(const char * file, unsigned line, const char * fmt, ...)
    {
        char buffer[256];
        va_list args;
        va_start(args, fmt);
        vsprintf(buffer, fmt, args);
        va_end(args);
    
        char buf[512];
        snprintf(buf, sizeof(buf), "%s:%i -> %s", file, line, buffer);
        python_error(buf);
    }
    
    void SetupNativeLogging(const char * logFileName)
    {
        /* Boiler plate init Python */
        Py_Initialize();
    
        /* Init our config module into Python memory */
        initPythonLoggingBackend();
    
        /* call directly into our cython module parseConfig */
        initLoggingWithLogFile(logFileName);
    }
    
    void CloseNativeLogging()
    {
        /* cleanup python before exit ... */
        Py_Finalize();
    }
    
    

    PythonLoggingBackend.pyx

    import logging
    
    cdef public void initLoggingWithLogFile(const char * logfile):
        logging.basicConfig(filename = logfile,
                            level = logging.DEBUG,
                            format = '%(levelname)s %(asctime)s: %(message)s',
                            datefmt = '%m/%d/%Y %I:%M:%S')
    
    cdef public void python_info(char * message):
        logging.info(message)
    
    cdef public void python_debug(char * message):
        logging.debug(message)
    
    cdef public void python_error(char * message):
        logging.error(message)
    
    

    Makefile

    all:
        cython -2 PythonLoggingBackend.pyx
        gcc -g -O2 -fpic -c PythonLoggingBackend.c -o PythonLoggingBackend.o `python-config --includes`
        gcc -g -O2 -fpic -c NativeLogging.c -o NativeLogging.o  `python-config --includes`
        gcc -g -O2 -fpic -c main.c -o main.o
        gcc -g -O2 -o example main.o PythonLoggingBackend.o NativeLogging.o `python-config --libs`
    
    clean:
        rm -f example PythonLoggingBackend.c *.o PythonLoggingBackend.h *.log
    
    

    相关文章

      网友评论

        本文标题:python高性能扩展工具-cython教程2基础

        本文链接:https://www.haomeiwen.com/subject/kornnftx.html