在经历过的一些大型项目中,很难独立使用一种开发语言完成任务,因为我这边的业务项目一般以服务器方面居多,从项目周期和运营维护角度考虑,既要考虑到程序的性能,又要考虑到业务功能变动和维护的便利性。
不少时候,咱们都会以Python进行框架开发,在一些涉及到性能要求的时候之内嵌C模块的形式进行扩展,以提升整个项目的执行效率。然而咱们还有不少以C语言开发的服务器项目,一般使用Prefork、MPM等多进程或多线程的框架,那么怎么才能作到灵活的对这些服务器程序的业务扩展或是Plugin功能呢?
之前在纯C语言时,咱们一般采用so lib或是dlopen的方法,这样每次增长或是调整业务模块都须要从新编译业务模块程序,使得联调和Debug相对比较复杂,如今咱们能够采用另外一种方式,在服务器端程序中嵌入Python解释器,在C程序中须要Kook的地方,以Python程序进行业务处理,灵活的实现Plugin机制,这样对于须要灵活业务调整、联调Debug时,带来了很大的便利性。python
如今以一个小的示例程序,介绍在C程序中如何嵌入Python解释器,及如何载入Python脚本程序。服务器
/** * @file test.c * gcc -Wall -O2 -o test test.c -I/usr/include/python2.7 -L/usr/lib -lpython2.7 -Wl,-R/usr/local/lib */ #include <stdio.h> #include <string.h> #include <Python.h> int main(int argc, char *argv[]) { PyObject *pmod = NULL; PyObject *pstr = NULL; PyObject *pfunc = NULL; PyObject *pargs = NULL; char *cstr = NULL; /* 初始化解释器 */ Py_Initialize(); /* 构建一个元组保存参数, PyEval_CallObject的第二参数是一个元组 */ pargs = Py_BuildValue("(s)", argv[1]); /* 添加Python路径, 包括当前路径, 不然不能导入当前路径下的模块 */ PyRun_SimpleString("import sys;sys.path.append('.')"); /* 导入模块名称, 一般为调用的Python脚本程序名 */ pmod = PyImport_ImportModule("testpy"); if (pmod == NULL) { printf("import module failed!\n"); return -1; } /* 得到导入模块的函数属性 */ pfunc = PyObject_GetAttrString(pmod, "testpy"); if (pfunc == NULL) { printf("No such attribute!\n"); return -1; } /* 调用导入模块的入口函数, 获取返回结果 */ pstr = PyEval_CallObject(pfunc, pargs); if (pstr == NULL) { printf("callobject failed!\n"); return -1; } /* 分析返回的结果 */ PyArg_Parse(pstr, "s", &cstr); printf("%s\n", cstr); /* 关闭解释器 */ Py_Finalize(); return 0; }
在C程序中嵌入的Python脚本程序示例,testpy.py:多线程
#!/usr/bin/env python import sys def testpy(name): if not name: return 'Valid Arguments' str = "hello, " + name return str
程序运行结果:app
~/prg/mypython$ ./test world!框架
hello, world!python2.7
一个更简单的例子:函数
/* * gcc -Wall -O2 -o test_python test_python.c -I/usr/include/python2.7 -L/usr/lib -lpython2.7 */ #include <Python.h> int main(int argc, char *argv[]) { Py_Initialize(); PyRun_SimpleString("from time import time,ctime"); PyRun_SimpleString("print 'Today is',ctime(time()) "); PyRun_SimpleString("print '^oo^'"); Py_Finalize(); return 0; }
$ ./test_python 性能
Today is Mon Mar 14 00:08:41 2016ui
^oo^spa