基本上读完了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 | Py_TPFLAGS_BASETYPE | GREENLET_GC_FLAGS, /* tp_flags */
"greenlet(run=None, parent=None) -> greenlet\n\n"
"Creates a new greenlet object (without running it).\n\n"
" - *run* -- The callable to invoke.\n"
" - *parent* -- The parent greenlet. The default is the current "
"greenlet.", /* tp_doc */
(traverseproc)GREENLET_tp_traverse, /* tp_traverse */
(inquiry)GREENLET_tp_clear, /* tp_clear */
0, /* tp_richcompare */
offsetof(PyGreenlet, weakreflist), /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
green_methods, /* tp_methods */ //对象方法的定义
0, /* tp_members */
green_getsets, /* tp_getset */ //属相方法
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
offsetof(PyGreenlet, dict), /* tp_dictoffset */ //这个对象的dict的偏移
(initproc)green_init, /* tp_init */ //初始化 这里主要是设置run以及parent
GREENLET_tp_alloc, /* tp_alloc */ //内存分配,其实也就是分配sizeof(PyGreenlet)的大小
green_new, /* tp_new */ //构造函数 这里会将parent默认的设置为全局的greenlet
GREENLET_tp_free, /* tp_free */ //释放
(inquiry)GREENLET_tp_is_gc, /* tp_is_gc */ //gc
};
这个里面构造以及初始化函数都提供了,那么先来看看构造函数吧,当在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, "|OO:green", kwlist,
&run, &nparent))
return -1;
if (run != NULL) { ///这里run对象是必须有的
//设置run对象
if (green_setrun(self, run, NULL))
return -1;
}
//这里在初始化的时候可以没有parent
if (nparent != NULL && nparent != Py_None)
//如果没有指定parent对象,那么将跟对象设置,在这个里面将会进行parent链是否存在环的情况进行判断
return green_setparent(self, nparent, NULL);
return 0;
}
这里初始化函数主要是设置构造的时候传递进来的执行函数,也就是run对象,然后就如果有传递parent的话,将会将这个greenlet对象的parent设置为传递进来的greenlet对象。。。。。
接下来来看看greenlet对象对应的一些方法的定义:
//这个就是暴露给greenlet对象的的方法了
static PyMethodDef green_methods[] = {
{"switch", (PyCFunction)green_switch, //switch方法的定义
METH_VARARGS | METH_KEYWORDS, green_switch_doc},
{"throw", (PyCFunction)green_throw, METH_VARARGS, green_throw_doc},
{"__getstate__", (PyCFunction)green_getstate, METH_NOARGS, NULL},
{NULL, NULL} /* sentinel */
};
这里就可以看到最为重要的switch方法其实对应的green_switch方法,。。嗯,那么接下来就来对照着如下python代码来分析greenlet吧:
from greenlet import greenlet
def test1(name):
print name
gr2.switch()
print "over"
def test2():
print "test-2"
return "test2-fjsfjs"
gr1 = greenlet(test1)
gr2 = greenlet(test2)
value = gr1.switch("fjsfjs")
print value
首先,得要先来看看greenlet模块的初始化:
PyMODINIT_FUNC
initgreenlet(void)
#endif
{
PyObject* m = NULL;
char** p = NULL;
PyObject *c_api_object;
static void *_PyGreenlet_API[PyGreenlet_API_pointers];
GREENLET_NOINLINE_INIT();
#if PY_MAJOR_VERSION >= 3
m = PyModule_Create(&greenlet_module_def);
#else
m = Py_InitModule("greenlet", GreenMethods); //初始化greenlet模块,这里其实定义的方法比较的少,getcurrent啥的
#endif
if (m == NULL)
{
INITERROR;
}
//为模块添加版本信息
if (PyModule_AddStringConstant(m, "__version__", GREENLET_VERSION) < 0)
{
INITERROR;
}
#if PY_MAJOR_VERSION >= 3
ts_curkey = PyUnicode_InternFromString("__greenlet_ts_curkey");
ts_delkey = PyUnicode_InternFromString("__greenlet_ts_delkey");
#if GREENLET_USE_TRACING
ts_tracekey = PyUnicode_InternFromString("__greenlet_ts_tracekey");
ts_event_switch = PyUnicode_InternFromString("switch");
ts_event_throw = PyUnicode_InternFromString("throw");
#endif
#else
ts_curkey = PyString_InternFromString("__greenlet_ts_curkey");
ts_delkey = PyString_InternFromString("__greenlet_ts_delkey");
#if GREENLET_USE_TRACING
ts_tracekey = PyString_InternFromString("__greenlet_ts_tracekey");
ts_event_switch = PyString_I