深入Cpython (编写一个Cpython 模块)
背景介绍
要深入一门语言,光知道编写业务很难深入。必须知道其内部原理才能写出更加优质的代码,特别是当设计到高并发程序的时候,你需要理解为什么有时候我们的多线程并不一定能够获得理想的效率,也许你知道GIL锁,但是不知道为什么它要存在?你也许知道可以通过使用多进程来替换多线程从而避免GIL但是你不知道我们还可以写C模块,然后用Python特有的胶水特性调用C从而避免GIL锁。当然说了那么多,总之就是想说我们需要深入Python,那么要深入一样东西必须找好入口,这个入口一旦找到就很容易思考各个模块的作用是什么了。
预备知识
因为不是人人都有Mac电脑,我就使用Linux来做演示,并且使用的是ubuntu版本。下面是准备系统编译环境
下载代码:
git clone https://github.com/python/cpython
cd cpython
git checkout <tag name> # 当前最新的tagid
构建工具安装,包含了gcc
和make
等
sudo apt install build-essential
接下来安装一些依赖库:
sudo apt install libssl-dev zlib1g-dev libncurses5-dev \
libncursesw5-dev libreadline-dev libsqlite3-dev libgdbm-dev \
libdb5.3-dev libbz2-dev libexpat1-dev liblzma-dev libffi-dev
配置及编译
为了在后续调试方便,我们在配置的时候选择一个debug
模式,这样会打印更多日志让我们参考:
./configure --with-pydebug
运行没有错误的话,可以进行下一步:
make -j2 -s
j2
代表启动两个job来加速编译,如果你CPU数量足够可以开启更多个,-s
代表silent安静的编译,即不打印消息。
运行测试
如果编译没有错误,这时候应该会在当前目录下生成一个python
可以执行文件。
./python
既可以运行
编写模块
要编写自己的模块需要遵循一定的规则,这些规则包含了内部定义的输入输出,错误日志及内存管理等。
进入到源码的cpython/Modules/
目录下,建立hellomodule.c
文件,然后开始撸代码。
#define PY_SSIZE_T_CLEAN
#include <Python.h>
static PyObject *
say_hello_ak(PyObject *self, PyObject *args)
{
const char * greeting = "hello\n";
int sts;
sts = printf("%s", greeting);
return PyLong_FromLong(sts);
}
static PyMethodDef helloMethods[] = {
{"say", say_hello_ak, METH_VARARGS, "say hello to frank ak .."},
{NULL, NULL, 0, NULL}
};
PyDoc_STRVAR(hello_doc, "this module is for someone who want to deep learn Python.\n\n ");
static struct PyModuleDef hellomodule = {
PyModuleDef_HEAD_INIT,
"hello",
hello_doc,
-1,
helloMethods
};
PyMODINIT_FUNC
PyInit_hello(void)
{
return PyModule_Create(&hellomodule);
}
在/Modules/Setup.local
中注册,让编译器知道有新的模块需要添加。
# Edit this file for local setup changes
hello hellomodule.o
在/Modules/config.c
中添加模块映射:
/* AK Add Module */
extern PyObject* PyInit_hello(void);
添加映射:
// ....
/* This lives in Objects/unicodeobject.c */
{"_string", PyInit__string},
/* AK registered Module */
{"hello", PyInit_hello},
/* Sentinel */
{0, 0}
再次编译
make
测试模块
总结
通过源代码构建自己的Python,然后编写一个模块认识模块编写规则,最好测试模块。这篇文章主要是先快速的让大家看到编写模块的流程,很多函数定义及规则没有细说,细心的读者或许看到我的Python终端显示了一个不同的图案,那是我在测试另一外一个功能的时候写入的,后续会介绍。