gevent中使用了greenlet库,greenlet是python的一个代码执行单元,或者说是一个协程,不同的协程间可以进行切换。

greenlet的栈数据分为两部分,一部分存在栈上,另一部分存在堆上,较为新的数据存在堆上,相对旧的数据在栈上,这两部分数据都可能为空。greenlets是相互链接的,每一个都指向先前的greenlet,先前的greenlet在栈上的数据在此greenlet之上(更旧点)。当前运行的greenlet就是此链的第一个元素,最早的greenlet(main greenlet)就是此链的最后一个元素。数据完全在堆上的greenlet就可以不在此链上。此链与执行顺序无关,只与特定时间C栈属于哪一个greenlet有关。

greenlet C源码部分函数:

static PyGreenlet *green_create_main(void)
// 1. 获取当前线程的线程状态dict
// 2. PyType_GenericAlloc初始化greenlet
// 3. 初始化main greenlet变量

static PyObject* green_statedict(PyGreenlet* g)
// 如果g未开始,则取其parent,如此一直取到开始的greenlet,返回其run_info。

static int g_save(PyGreenlet* g, char* stop)
// 保存g的栈数据至stop处

static void GREENLET_NOINLINE(slp_restore_state)(void)
// 1. 恢复ts_target的栈数据
// 2. 恢复ts_target的stack_prev

static int GREENLET_NOINLINE(slp_save_state)(char *stackref)
// 保存ts_target->stack_stop下的greenlet的栈数据

static int g_switchstack(void)
// 根据提前设置好的全局变量作栈切换:
//   ts_current: 当前greenlet --强引用
//   ts_target: 切换的目标greenlet --弱引用
//   ts_passaround_args: 传递给ts_target的参数(tuple)
// 函数执行后返回结果同样用全局变量传递:
//   ts_origin: 原始greenlet --强引用
//   ts_current: 当前greenlet --弱引用
//   ts_passaround_args: 传递给ts_current的参数(tuple)
// 栈切换需要保证是原子操作,也就是说调用python代码是不允许的(除了少数安全的),因为全局变量是非常容易破坏的。

static PyObject *g_switch(PyGreenlet* target, PyObject* args, PyObject* kwargs)
// 1. 向上(parent)找到真正的target,忽略死掉的greenlet,必要的话启动一个greenlet。
// 2. g_switchstack
// 3. 返回参数

static PyObject *g_handle_exit(PyObject *result)
// 处理返回值,异常处理,或者用tuple返回

static int GREENLET_NOLINE(g_initialstub)(void* mark)
// 1. 初始化ts_target相关变量
// 2. g_switchstack
// 3. 调用ts_target(self)的run函数
// 4. run函数result返回
// 5. g_switch切换到其父greenlet

static PyObject* green_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
// PyBaseObject_Type.tp_new 创建新的greenlet

static int green_init(PyGreenlet *self, PyObject *args, PyObject *kwargs)
// 1. 从args, kwargs解析run parent
// 2. 设置self的run,和parent

static int kill_greenlet(PyGreenlet* self)
// 1. self必须在当前线程执行,否则在其线程dict中存del_key
// 2. g_switch切换到self的parent

static void green_dealloc(PyGreenlet* self)
// 1. kill_greenlet(self)
// 2. free memory

static PyObject* single_result(PyObject* results)
// return results

static PyObject *throw_greenlet(PyGreenlet *self, PyObject *typ, PyObject *val, PyObject *tb)
// 异常处理,然后退出self

static PyObject *green_switch(PyGreenlet *self, PyObject *args, PyObject *kwargs)
// g_switch

static PyObject *green_throw(PyGreenlet *self, PyObject *args)
// throw_greenlet

static int green_bool(PyGreenlet *self)
// 是否active

static PyObject *green_getdict(PyGreenlet *self, void *c)
// return dict

static int green_setdict(PyGreenlet *self, PyObject *val, void *c)
// set dict

static PyObject *green_getdead(PyGreenlet *self, void *c)
// return if dead

static PyObject *green_get_stack_saved(PyGreenlet *self, void *)
// return stack_saved size

static PyObject *green_getrun(PyGreenlet *self, void *c)
// return run_info

static int green_setrun(PyGreenlet *self, PyObject *nrun, void *c)
// set run info

static PyObject *green_getparent(PyGreenlet *self, void *c)
// return self->parent

static int green_setparent(PyGreenlet *self, PyObject *nparent, void *c)
// set parent

static PyObject *green_getframe(PyGreenlet *self, void *c)
// return top_frame

static PyObject *green_getstate(PyGreenlet *self)
// NULL

greenlet的执行流程

  1. import greenlet, 创建main greenlet
  2. 创建新的greenlet实例,设置run函数
  3. switch,切换状态,保存状态,执行,恢复状态

greenlet核心思想

保存栈数据,切换到新的代码段执行后,恢复栈数据,继续执行原代码

comments powered by Disqus