pyston的generator实现


1. python的generator是啥?

 

就是一个能够当做iterator使用的function。例如如下常用的玩意

 

for i in range(10):
   print i

 

2. 这东西难不难实现?

如果不允许用户自定义generator函数,就range这种内置的东西而言,不难实现。把range定义成一个类的对象,通过内部状态维护当前的值,在定义诸如next的方法就ok了。但是如果允许用户定义这种函数就有点要命了。例如如下的代码:

 

 

def forfun():
 yield hello
 yield world

def forfun1(n):
  i = 0
  while i < 10 :
     if i < n:
       yield i
     else :
       yield i * 10
     i = i + 1
这下就比较要命了,forfun和forfun1被编译成函数,可是函数是没状态的(static这种就不提了),每次执行不可能接着上次返回之后继续来。在pyston中,其实generator的实现类似与co-route.

3. ucontex这么个东西

参见:http://linux.die.net/man/3/swapcontext

通过getcontex这个函数,我们可以获得一个ucontex_t类型的实例,在通过makecontext函数修改这个实例,makecontext需要提供被调用的函数,参数列表。例如那个页面里面的一段代码:

 

uctx_func1.uc_stack.ss_sp = func1_stack;
uctx_func1.uc_stack.ss_size = sizeof(func1_stack);
uctx_func1.uc_link = &uctx_main;
makecontext(&uctx_func1, func1, 0);

 

uctx_func1就是通过getconext获取的,首先我们需要设置它执行函数时使用的栈,栈的大小,uc_link应该就是调用它所服务的那个函数的context。

现在是如何在每个函数之间跳来跳去,还能保证回到原函数时,继续执行之前跳出的代码之后的代码。关键是swapcontext函数,它会把当前的context保存在第一个指针指向的ucontext_t,然后执行第二个指针所保存的文境。

 

4.generator怎么实现的呢

实现generator表达式或者函数都是BoxedGenerator类型的一个对象,这个类记录了用户定义的generator函数执行的stack,并且包含两个ucontext_t类型的变量context和returncontext。客户端在不断的调用它的next函数时,其实执行的流程如下:

next->generatorNext -> generatorSend(注意,里面调用了swapcontext(&self->returnContext,&self->context);)->跳至用户定义的函数->用户定义代码中执行yield,调用实现函数yield

->yield(它干啥里,就是调用swapcontext(&self->context,&self->returnContext);)

->这时执行流程又回到了generatorSend,开始执行swapcontext下一条指令。

这里还漏了一点,也就是第一次调用next的时候,context的值从何而来,这个关键在BoxGenerator的够着函数中了,代码如下:

 

getcontext(&context);
    context.uc_link = 0;
    context.uc_stack.ss_sp = stack;
    context.uc_stack.ss_size = STACK_SIZE;
    makecontext(&context, (void (*)(void))generatorEntry, 1, this);

而在generatorEntry中就会调用用户定义的代码。然后这个环就链上了,用户定义的代码里面有yield,yield又会回到generatorSend,哈,拿到了需要的结果。

 

 

 
 

相关内容

    暂无相关文章

评论关闭