自从看了《Python源码剖析》,越来越觉得这是一本操作系统入门书籍。毕竟虚拟机也带有点操作系统的味道,今天逛google,发现以前的一个好朋友也在用Python。以前什么事情都是被她超越,这次不能输给她了。随着对Python的深入,我现在开始明白数据结构的重要性了。只有明白了数据结构和一些常用算法,才能有机会对操作系统绝对清晰。熟悉汇编也是清晰操作系统的必经之路(因为汇编涉及了x86架构)。好了,废话不多说,进入正题。
上面这段话是我昨天写的,今天我看了Python源码的整数部分。先不说Python中整数系统,我先说说看这一章的感受。感受最大的就是C语言,大一的时候学了一点C语言的语法,之后就没有写C了。现在看C代码来真心相当吃力,之前还一直没有体会,这可能跟我那糟糕的数据结构有关,现在越来越明白数据结构的重要性,越来越明白C语言和数据结构是密不可分的东西,它与一些高级语言不一样,高级语言一般都把内存操作封装了,让你可以把注意力集中在业务逻辑上面。不懂C和数据结构的人永远没法绝对清晰。
在Python中整数是通过PyIntObject对象来实现的,PyIntObject是一个immutable(不可变对象),所谓不可变对象就是说PyIntObject所维护的值是永远不会变化的,也正是由于这些不变性,才实现了Python整数池机制。
typedef struct {
PyObject_HEAD
long ob_ival;
} PyIntObject;
Python中整数对象只不过是对C中long类型的一个包装(加上了类型信息和引用计数)。对象的元信息都是存放在类型对象上的,而PyIntObject的类型是PyInt_Type
PyTypeObject PyInt_Type = {
PyObject_HEAD_INIT(&PyType_Type)
0,
"int", /* 名字 */
sizeof(PyIntObject), /* 创建时候内存大小 */
0,
(destructor)int_dealloc, /* 析钩函数 */
(printfunc)int_print, /* print方法 */
0, /* tp_getattr 跟tp_getattro类似,不过已经呗弃用 */
0, /* tp_setter 跟tp_setattro类似,不过已经被弃用 */
(cmpfunc)int_compare, /* 比较操作 */
(reprfunc)int_repr, /* tp_repr repr()调用的方法*/
&int_as_number, /* tp_as_number 数值类型操作的集合 */
0, /* tp_as_sequence 序列类型操作的集合 */
0, /* tp_as_mapping map类型操作的集合 */
(hashfunc)int_hash, /* tp_hash 计算哈希值的方法 */
0, /* tp_call 这个我表示不可理解,int明明十一个可调用对象为什么这里会是0 */
(reprfunc)int_repr, /* tp_str str()调用的方法 */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer 不知道是干嘛用的 */
PyTPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES | PyTPFLAGS——BASETYPE /* tp_flags */
int_doc, /* tp_doc __doc__ */
0, /* tp_traverse 不知道是干嘛用的*/
0, /* tp_clear 不知道是干嘛用的*/
0, /* tp_richcompare 富比较 */
0, /* tp_weaklistoffset */
0, /* tp_iter 创建迭代器 */
0, /* tp_iternext 迭代器的next()方法 */
int_methods, /* tp_methods 成员函数集合 */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get 一个descript */
0, /* tp_descr_set 一个descript */
0, /* tp_dictoffset */
0, /* tp_init 初始化方法 */
0, /* tp_alloc 申请内存 */
int_new, /* tp_new 申请内存 */
(freefunc)int_free, /* tp_free 释放内存 */
}
static PyNumberMethods int_as_number = {
(binaryfunc)int_add, /* nb_add */
(binaryfunc)int_sub, /* nb_subtract */
...
(binaryfunc)int_div, /* nb_floor_divide */
int_true_divide, /* nb_true_divide */
0, /* nb_inplace_floor_divide floor_divide*/
0, /* nb_inplace_true_divide 真除*/
}
[intobject.h]
// 牺牲类型安全换取效率
#define PyInt_AS_LONG(op) (((PyIntObject *)(op)) -> ob_ival)
[intobject.c]
#define CONVERT_TO_LONG(obj, lng) \
if (PyInt_Check(obj)) { \
lng = PyInt_AS_LONG(obj); \
} \
else {
Py_INCREF(Py_NotImplemented); \
return Py_NotImplemented; \
}
好吧,其实我还看到了int类型的__doc__,这个坑爹的东西昨天坑我到一点多。
Python提供了3种途径用来创建PyIntObject对象
PyObject* PyInt_FromeLong(long ival)
PyObject* PyInt_FromString(char *s, char **pend, int base)
#ifdef Py_USING_UNICODE
PyObject* PyInt_FromUnicode(Py_UNICODE *s, int length, int base)
#endif
今天还看到一句很牛逼的话:在Python中,所有的对象都是存活在系统堆上的。对于什么是系统堆我现在还没概念,所以操作系统真的很重要。不然永远不可能绝对清晰。
由于整数对象十分常用,如果频繁得申请释放内存会导致Python性能低下,所以这里采用了整数池的方式来提高性能(我个人觉得这个设计很牛逼,有些事情一个人做不了,但是如果一群人能做得更好)。整数池又分为小整数池和大整数池,这两者的差别在于一个是全部缓存(小整数),一个是部分缓存(大整数)。
小整数池在Python虚拟机激活的时候就会创建,那个时候申请一块内存,将常用的小整数(默认5-257)放在里面,需要用的时候去里面拿,永远也不会销毁。
大整数池是需要用到小整数之外的整数时,去操作系统申请一块内存,用来存放创建的整数,并缓存在这里,下次用的时候来这里拿。如果内存不够了,继续向操作系统申请。这些内存抽象成一个单向链表,由block_list维护,其中的所有空闲内存由free_list维护(也是一条单向链表)。
#define BLOCK_SIZE 1000
#define BHEAD_SIZE 8
#define N_INTOBJECTS ((BLOCK_SIZE - BHEAD_SIZE) / sizeof(PyIntObject))
struct _intblock {
struct _intblock *next;
PyIntObject objects[N_INTOBJECTS];
};
typedef struct _intblock PyIntBlock;
static PyIntBlock *block_list = NULL;
static PyIntObject *free_list = NULL;
创建和删除整数
PyObject* PyInt_FromLong(long ival)
{
register PyIntObject *v;
#if NSMALLNEGINTS + NSMALLPOSINTS > 0
if (-NSMALLNEGINTS <= ival="" &&="" <="" nsmallposints)="" {="" v="small_ints[ival" +="" nsmallnegints];="" py_incref(v);="" return="" (pyobject="" *)="" v;="" }="" #endif="" [2]:为通用整数对象池申请新的空间="" if="" (free_list="=" null)="" ((free_list="fill_free_list())" =="NULL)" null;="" [3]:(inline)内嵌pyobject_new的行为="" free_list="(PyIntObject" *)v="" -=""> ob_type;
PyObject_INIT(v, &PyInt_Type);
v -> ob_ival = ival;
return (PyObject *)v;
}
=>
睡觉了,明天再写。祝贺今天张聪学长升职。