内容简介:Tensorflow 的核心代码是 C 和 C++ 实现然后提供 Python 的接口,使用者无需关心 C++ 的细节,直接使用 Python 就能调用相关功能,而且这些功能多是比较复杂且耗时的操作。类似的有 caffe , xgboost 的工具包。C++ 和 Python 之间的交互有很多种,而且在不同场景下可以选择不同的方式。这篇文章列举一些常用的方式,并给出简单的例子方便理解和选择不同方式来解决自己的问题。Python 官方文档介绍了直接在 C 中调用 CPython
C/C++ 和 Python 之间的交互
Tensorflow 的核心代码是 C 和 C++ 实现然后提供 Python 的接口,使用者无需关心 C++ 的细节,直接使用 Python 就能调用相关功能,而且这些功能多是比较复杂且耗时的操作。类似的有 caffe , xgboost 的 工具 包。
C++ 和 Python 之间的交互有很多种,而且在不同场景下可以选择不同的方式。这篇文章列举一些常用的方式,并给出简单的例子方便理解和选择不同方式来解决自己的问题。
直接调用 CPython 的接口
Python 官方文档介绍了直接在 C 中调用 CPython 接口
的方式来实现 Python 扩展。这需要了解 Python 提供的接口,然后利用 distutils/setuptools 来构建扩展 如下面的例子,C 代码是现在 hello.c
文件中,然后写 setup.py
运行 python setup.py build_ext —inplace
然后就可以在当前目录下直接 import hello
include <stdio.h>
#include <Python.h>
static PyObject* hello_world(PyObject *self, PyObject *args) {
printf("Hello, world!\n");
Py_RETURN_NONE;
}
static PyObject* hello(PyObject *self, PyObject *args) {
const char* name;
if (!PyArg_ParseTuple(args, "s", &name)) {
return NULL;
}
printf("Hello, %s!\n", name);
Py_RETURN_NONE;
}
static PyMethodDef hello_methods[] = {
{
"hello_world", hello_world, METH_NOARGS,
"Print 'hello world' from a method defined in a C extension."
},
{
"hello", hello, METH_VARARGS,
"Print 'hello xxx' from a method defined in a C extension."
},
{NULL, NULL, 0, NULL}
};
static struct PyModuleDef hello_definition = {
PyModuleDef_HEAD_INIT,
"hello",
"A Python module that prints 'hello world' from C code.",
-1,
hello_methods
};
PyMODINIT_FUNC PyInit_hello(void) {
Py_Initialize();
return PyModule_Create(&hello_definition);
}
# setup.py
from distutils.core import setup, Extension
hello_module = Extension('hello', sources = ['hello.c'])
setup(name='hello',
version='0.1.0',
description='Hello world module written in C',
ext_modules=[hello_module])
官放还提供了一种方式直接把整个 CPython 嵌入到项目里,有需要可以查看 详细文档
Cython
按官方的实现方式我们需要按照 C/C++ 去实现功能, Cython
的想法是用 Python 本身的语法去实现功能,然后 Cython 会翻译 对应的 .c
文件,然后按照上面的方式利用 distutils/setuptools 来构建扩展。Cython 的实现一般放在 .pyx
的后缀文件中。下面还是一个例子.
hello.pyx
def say_hello_to(name):
print("Hello %s!" % name)
setup.py
rom distutils.core import setup
from Cython.Build import cythonize
setup(name='Hello world app',
ext_modules=cythonize("hello.pyx"))
在当前目录执行 python setup.py build_ext —inplace
可以得到动态对应的 .c
文件和编译好的动态链接库。
在当前目录可以直接import 当然你可以 python setup.py install
来安装到系统下。
ctypes
这是在 Python 官方标准库中实现的包,相对于直接调用 CPython 的接口的优雅之处在于,我们只需要写 C 代码然后剩下的交给 ctypes 去处理接好了,我们不需要去花时间了解 CPython 的接口。
hello.c
#include <stdio.h>
void hello(void);
void hello()
{
printf("hello world");
}
编译: gcc -shared -Wl,-install_name,hello.so -o hello.so -fPIC hello.c
然后就可以在 ```hello.py`` 中直接调用
hello.py
import ctypes
hello = ctypes.CDLL('hello.so')
hello.hello()
类似的还有 cffi
swig
swig
强大之处在于可以把 C/C++ 写的东西和十几种其他语言进行交互,这其中就包括 Python 。但是也需要我们写一个 .i
后缀的接口文件。swig 有优势也有很多不足, Stack Overflow
的比较 ctypes 和 swig 的问题下一答者记录了他在使用 Swig 不同时间段的不同感受. Tensorflow 的实现方式就是利用了 swig 来实现的。下面是一个官方的例子.
example.c
#include <time.h>
double My_variable = 3.0;
int fact(int n) {
if (n <= 1) return 1;
else return n*fact(n-1);
}
int my_mod(int x, int y) {
return (x%y);
}
char *get_time()
{
time_t ltime;
time(<ime);
return ctime(<ime);
}
example.i
/* example.i */
%module example
%{
/* Put header files here or function declarations like below */
extern double My_variable;
extern int fact(int n);
extern int my_mod(int x, int y);
extern char *get_time();
%}
extern double My_variable;
extern int fact(int n);
extern int my_mod(int x, int y);
extern char *get_time();
构建
swig -python example.i gcc -c example.c example_wrap.c -I/usr/local/include/python2.7 ld -shared example.o example_wrap.o -o _example.so
当然可以自己修改 Python 的路径
使用的时候就直接在 Python 中 import example
pybind11
如果是使用 C++ 还可以用 pybind11 https://github.com/pybind/pybind11 比 swig 更轻,与之类似的还有 Boost.Python caffe 的 Python 就可以用 Boost.Python 编译。如果你主要使用的语言是 C++ 但是要给使用 Python 的用户提供相对友好的接口就可以使用这种方式。
example.c
#include <pybind11/pybind11.h>
int add(int i, int j) {
return i + j;
}
PYBIND11_MODULE(example, m) {
m.doc() = "pybind11 example plugin"; // optional module docstring
m.def("add", &add, "A function which adds two numbers");
}
编译
c++ -O3 -Wall -shared -std=c++11 -fPIC `python3 -m pybind11 --includes` example.cpp -o example`python3-config --extension-suffix`
然后就可以在 Python 中直接导入了,前提是的安装 pybind11 。
总结
Python 语言本身是一种表达方式,通过 Python 解释器翻译成其他语言,由于 CPython 是 C 语言实现所有比较方便的可以在 C/C++ 和 Python 之间进行调用,问题就是这个翻译工作谁来做,怎么做,以及翻译方式是否方便和维护。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 用js简单提供增删改查接口
- 怎样提供一个好的移动 API 接口服务
- 带入gRPC:让你的服务同时提供 HTTP 接口
- WeiXinMPSDK 发布最新稳定版,大幅提升效率,提供新接口!
- WeiXinMPSDK 4.5.1 发布,大幅提升效率,提供新接口!
- Torna 1.8.0 发布,支持接口聚合,提供 Swagger 插件
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
遗传算法与工程优化
程润伟 / 清华大学出版社 / 2004-1 / 39.00元
《遗传算法与工程优化》总结了遗传算法在工业工程相关领域应用的前沿进展。全书共分9章:遗传算法基础、组合优化问题、多目标优化问题、模糊优化问题、可靠性设计问题、调度问题、高级运输问题、网络设计与路径问题和制造元设计问题。内容既涵盖了遗传算法在传统优化问题中的新进展,又涉及了目前在供应链和物流研究中相当热门的话题。一起来看看 《遗传算法与工程优化》 这本书的介绍吧!