Several ways python and C language calling each other

Python limelight all these years has been very Sheng, occupy the position of many areas, Web, Big Data, artificial intelligence, operation and maintenance are in its presence, even a graphical interface to do is also very smooth, and even full-stack the words just came out, , it seems to describe it.

Although Python's GIL problem causes can not take advantage of multicore multithreading, but later multiprocess from the perspective of multiple processes to take advantage of multi-core, or even affinity to bind specific CPU core, this issue can be considered resolved. Although the basic language for the whole stack, but sometimes the interest of efficiency, may still be to consider and C language mixed.

Mixed in a computer is an unavoidable topic, involves many things, technology, architecture, team, the management, its customers and other links may have an impact, I think, when mixed this problem to open a special discussion. C and mixed talk python herein manner substantially the following ways (herein background linux, other platforms is analogous):

Shared Libraries

Using C language compiler to produce a shared library, and then use cdll ctype python library to open a shared library.

By way of example as follows, C language code

/* func.c */
int func(int a)
{
        return a*a;
}

python code

#!/usr/bin/env python
#test_so.py
from ctypes import cdll
import os

p = os.getcwd() + '/libfunc.so'
f = cdll.LoadLibrary(p)
print f.func(99)

Tests are as follows

$ gcc -fPIC -shared func.c -o libfunc.so
$ ./test_so.py
9801

subprocess

C language design a complete executable file, and then to execute the python executable by subprocess, a fork + execve nature.

By way of example as follows, C language code

/* test.c */
#include <stdio.h>
int func(int a)
{
        return a*a;
}

int main(int argc, char **argv)
{
        int x;

        sscanf(argv[1], "%d", &x);
        printf("%d\n", func(x));
        return 0;
}

Python code

#!/usr/bin/env python
# test_subprocess.py
import os
import subprocess

subprocess.call([os.getcwd()+'/a.out', '99'])

Tests are as follows

$ gcc test.c -o a.out
$ ./test_subprocess.py
9801

C language program run python

C language using popen / system or directly to the system call level fork + exec to run the python program is also a means of mixed up.

By way of example as follows, Python code is as follows

#!/usr/bin/env python
# test.py
import sys
x = int(sys.argv[1])
print x*x

C language code as follows

/* test.c */
#include <stdio.h>
#include <stdlib.h>
int main()
{
        FILE *f;
        char s[1024];
        int ret;

        f = popen("./test.py 99", "r");
        while((ret=fread(s,1,1024,f))>0) {
                fwrite(s,1,ret,stdout);
        }
        fclose(f);
        return 0;
}

Tests are as follows

$ gcc test.c
$ ./a.out
9801

 
python support for C language extensions

Many programming languages ​​as C language extensions add support for these two reasons: (1) at the beginning of language design, we can fully utilize the existing C language library to do a lot of expansion; high efficiency (2) C language .

python is no exception, since its birth, many libraries are written in C language. C-language extensions python involved in C language data structure of the python, the extension method is written in C language is actually a shared library, only the shared library interface is a standard, the python can be identified.

To illustrate how to extend, I am here to assume the function of a function in python, the code is as follows

def func(*a):
    res=1
    for i in range(len(a)):
        res *= sum(a[i])
    return res

As above, the desired function is a function of the parameter is any of a list of a plurality of digits (temporary exclusion of other data structures), and returns the product of the elements of each list.

A first temporary python code written as follows

#!/usr/bin/env python
# test.py
import colin

def func(*a):
    res=1
    for i in range(len(a)):
        res *= sum(a[i])
    return res

a = [1,2,3]
b = [4,5,6]
c = [7,8]
d = [9]
e = [10,11,12,13,14]

f = colin.func2(99)
g = colin.func3(a,b,c,d,e)
h = func3(a,b,c,d,e)
print "f = ",f
print "g = ",g
print "h = ",h

Before the test has been put on the square func, this relatively simple, consistent python want to write out the func C language extensions and can out the results.

The first written in C language implementation of these functions, wherein func3 spend data representing a plurality of arbitrary array of structures Y_t arbitrarily long, and x_t used to represent a single array.

/* colin.h */
#ifndef Colin_h
#define Colin_h
typedef struct {
        int *a;
        int len;
} x_t;
typedef struct {
        x_t *ax;
        int len;
} y_t;
int func2(int a);
int func3(y_t *p);
void free_y_t(y_t *p);
#endif
/* colin.c */
#include "colin.h"
#include <stdlib.h>

int func2(int a)
{
        return a*a;
}

int func3(y_t *p)
{
        int result;
        int sum;
        int i, j;

        result = 1;
        for(i=0;i<p->len;i++) {
                sum = 0;
                for(j=0;j<p->ax[i].len;j++)
                        sum += p->ax[i].a[j];
                result *= sum;
        }

        return result;
}

void free_y_t(y_t *p)
{
        int i;
        for(i=0;i<p->len;i++) {
                free(p->ax[i].a);
        }
        free(p->ax);
}

Defined above three functions, func2 on behalf of the square, said before representatives func3 function, because, so a return to the memory of this method y_t structure may have been dynamically allocated out.

Python extensions have said, then, need to interface to the shared library "standardized" look. So we look at the packaging and loading entrance to a python.

/* wrap.c */
#include <Python.h>
#include <stdlib.h>
#include "colin.h"
PyObject* wrap_func2(PyObject* self, PyObject* args)
{
        int n, result;
        /* 从参数列表中导出一个整形,用"i" */
        if (!PyArg_ParseTuple(args, "i", &n))
                return NULL;

        /* 用C语言的库实现来计算 */
        result = func2(n);
        /* 计算结果必须要导成python识别的类型 */
        return Py_BuildValue("i", result);
}

PyObject* wrap_func3(PyObject* self, PyObject* args)
{
        int n, result;
        int i, j;
        int size, size2;
        PyObject *p,*q;
        y_t *y;

        y = malloc(sizeof(y_t));
        /* 先数数有多少个参数,也就是列表的个数 */
        size = PyTuple_Size(args);
        /* 把数组的个数先分配了 */
        y->len = size;
        y->ax = malloc(sizeof(x_t)*size);
        /* 遍历python里各个列表(参数) */
        for(i=0;i<size;i++) {
                /* 先获得第i个参数,是一个列表 */
                p = PyTuple_GetItem(args, i);
                /* 获得列表的长度 */
                size2 = PyList_Size(p);
                /* 为数组分配好空间 */
                y->ax[i].len = size2;
                y->ax[i].a = malloc(sizeof(int)*size2);
                /* 遍历列表,依次把列表里的数转到数组里 */
                for(j=0;j<size2;j++) {
                        q = PyList_GetItem(p, j);
                        PyArg_Parse(q,"i",&y->ax[i].a[j]);
                }
        }

        /* 用C语言的库实现来计算 */
        result = func3(y);
        free_y_t(y);
        free(y);
        /* 结果转成python识别格式 */
        return Py_BuildValue("i", result);
}

/* 这是接口列表,加载时是只加载此列表的地址,所以这个数据结构不能放栈(局部变量)内,会被清掉 */
static PyMethodDef colinMethods[] =
{
        {"func2", wrap_func2, METH_VARARGS, "Just a test"},
        {"func3", wrap_func3, METH_VARARGS, "Just a test"},
        {NULL, NULL, METH_NOARGS, NULL}
};

/* python加载的时候的接口 */
/* 注意,既然库名叫colin,此函数必须交initcolin */
void initcolin()
{
        PyObject *m;
        m = Py_InitModule("colin", colinMethods);
}

Process, I guess PyArg_VaParse should be more powerful, but repeated measurements did not succeed, did not look the document.

have a test

$ gcc -I /usr/include/python2.7/ -fPIC -shared colin.c wrap.c -o colin.so
$ ./test.py
f =  9801
g =  729000
h =  729000

You can see, the same functions written in C language functions written in python and results.

Guess you like

Origin www.cnblogs.com/python960410445/p/11953904.html