python协程的实现(greenlet源码分析)

发布时间:2017-09-05 11:49:07
python协程的实现(greenlet源码分析)

基本上读完了greenlet的源代码,代码不多,就2000行C语言的代码,其中有一部分栈寄存器的修改的代码是由汇编实现的。。。

一句话来说明greenlet的实现原理:通过栈的复制切换来实现不同协程之间的切换。。。

那么接下里来具体的来看看greenlet的代码到底是怎么实现的。。。


好了,先来看看greenlet对象对应的C语言结构体:/** States: stack_stop == NULL && stack_start == NULL: did not start yet stack_stop != NULL && stack_start == NULL: already finished stack_stop != NULL && stack_start != NULL: active **/ //greenlet对象最终对应的数据的C结构体,这里可以理解为python对象的属性 typedef struct _greenlet PyObject_HEAD char* stack_start; //栈的顶部 将这里弄成null,标示已经结束了 char* stack_stop; //栈的底部 char* stack_copy; //栈保存到的内存地址 intptr_t stack_saved; //栈保存在外面的大小 struct _greenlet* stack_prev; //栈之间的上下层关系 struct _greenlet* parent; //父对象 PyObject* run_info; //其实也就是run对象 struct _frame* top_frame; //这里可以理解为主要是控制python程序计数器 int recursion_depth; //栈深度 PyObject* weakreflist; PyObject* exc_type; PyObject* exc_value; PyObject* exc_traceback; PyObject* dict; PyGreenlet;

这里stack_start,stack_stop就是用于分别指向当前这个协程的栈的顶部与栈的底部,而且可以通过这几个标志位的值来判断当前这个greenlet对象的状态。。。

另外这里可以看到parent指针,用这个来构成greenlet对象的层次关系。。。

接下来来看看与python对象之间对应关系://这个是定义的暴露给python的greenlet对象,它以greenlet.h里面定义的_greenlet位基础,然后指定了方法,创建方法等 PyTypeObject PyGreenlet_Type = PyVarObject_HEAD_INIT(NULL, 0) "greenlet.greenlet", /* tp_name */ sizeof(PyGreenlet), /* tp_basicsize */ //指定对象的大小,其实也就是结构体的大小 0, /* tp_itemsize */ /* methods */ (destructor)green_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ 0, /* tp_repr */ &green_as_number, /* tp_as _number*/ 0, /* tp_as _sequence*/ 0, /* tp_as _mapping*/ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer*/ Py_TPFLAGS_DEFAULT;

这个里面构造以及初始化函数都提供了,那么先来看看构造函数吧,当在python中执行环境中创建greenlet对象的时候,将会先调用green_new方法,接着调用green_init方法。。。//创建一个greenlet对象,这个可以理解为greenlet的构造函数 //这里会先将parent默认指向当前环境所属的greenlet对象 //如果在greenlet对象的构造函数中带有parent对象,那么待会在init中会设置 static PyObject* green_new(PyTypeObject *type, PyObject *args, PyObject *kwds) PyObject* o; if (!STATE_OK) return NULL; //先用基本对象来构造 o = PyBaseObject_Type.tp_new(type, ts_empty_tuple, ts_empty_dict); if (o != NULL) //这里默认将parent设置为ts_current,也就是在哪一个greenlet环境里面创建的,那么新创建的greenlet的parent就是所属的环境greenlet Py_INCREF(ts_current); ((PyGreenlet*) o)->parent = ts_current; return o;

这个代码很好理解吧,先构造父类,接着设置当前greenlet的默认parent,这里可以看到将parent默认的设置为当前环境所属的greenlet对象,也就是说假如我们在A中创建另外一个greenlet B,而且构造函数中没有传递parent参数,这个并没有关系,因为默认就已经将B的parent设置为A了...

好了,接下来来看看初始化函数://初始化greenlet对象,这个可以理解为在构造之后,将会调用这个方法来进行初始化,主要是检查设置run,以及设置parent //这里可能没有parent参数,不过也没有关系,因为在构造的时候就先设置为创建环境的greenlet static int green_init(PyGreenlet *self, PyObject *args, PyObject *kwargs) PyObject *run = NULL; PyObject* nparent = NULL; //看当前这两个东西是否存在 static char *kwlist[] = "run", "parent", 0; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "

这里初始化函数主要是设置构造的时候传递进来的执行函数,也就是run对象,然后就如果有传递parent的话,将会将这个greenlet对象的parent设置为传递进来的greenlet对象。。。。。

接下来来看看greenlet对象对应的一些方法的定义:

企业建站2800元起,携手武汉肥猫科技,做一个有见地的颜值派!更多优惠请戳:武汉网站制作 http://www.feimao666.com


友情链接

独家出品

新闻由机器选取每5分钟自动更新

新闻搜索源于互联网新闻网站和频道,系自动分类排列,本站不刊登或转载任何完整的新闻内容