Differences between revisions 3 and 4
Revision 3 as of 2006-09-05 09:14:03
Size: 4783
Editor: HuangYi
Comment: 加点注释
Revision 4 as of 2006-12-02 04:45:35
Size: 95
Editor: HuangYi
Comment:
Deletions are marked like this. Additions are marked like this.
Line 1: Line 1:
["huangyi"]/2006-09-05.

今天邮件列表里讨论 python2.5 中增强的yield特性,讨论得热火朝天。

顿觉心血来潮,就用这增强型的 yield 大致模拟了下 StacklessPython 的 api。

虽然不能一模一样,不过感觉也只能做到这一步了。

主要是因为相对 StacklessPython 来说 yield 有这么几个限制:

 * 函数只能通过 yield 来挂起,这导致实现 channel 的时候只能通过 {{{yield command(c.send, value)}}},{{{value = yield command(c.receive)}}} 这样的语法来使当前 tasklet 挂起 (一定条件下) ,不像 stacklesspython 直接 some_channel.send(...) 就有可能挂起当前 tasklet 。
 * yield 只能向上一层,而不能直接 yield 到调用栈的最上层(或者甚至是指定 yield 到哪一层!!),这导致我们的 tasklet 只能在函数调用的第一层进行 yield 才能将执行权切换给调度程序,像下面:
{{{#!python
def a_task():
    a_func()
def a_func():
    # 在这个函数里是没用办法将执行权切换给调度程序的。
}}}
不像 StacklessPython ,随便哪里调用 stackless.schedule() 都可以把执行权交出去。

谁叫人家c写的呢。:(

本来还想把 ["evolution"] 也转过来的,发现 pygame 还没为 windows 编译 python2.5 的版本,自己编译太麻烦,还是等 python2.5 正式发布了再说吧。

 * 注意:运行下面程序需要 python2.5

{{{#!python
#coding:utf-8
from collections import deque

'''
http://www.stackless.com/
'''

debuglevel = 0

readys = deque() # 就绪队列

class command(object):
    def __init__(self, func, *args, **kw):
        self.func = func
        self.args = args
        self.kw = kw

    def __call__(self, task):
        return self.func(task, *self.args, **self.kw)

class channel(object):
    ''' http://www.stackless.com/wiki/Channels '''
    def __init__(self):
        self.senders = deque() # 发送队列 元素:(tasklet, obj)
        self.receivers = deque() # 接收队列 元素:tasklet

    def send(self, sender, obj):
        '''向channel中发送数据,如果没用接受者,则让该tasklet等待'''
        if debuglevel:
            print 'tasklet:',sender,'send data:',obj,';receivers:',len(self.receivers)
        if self.receivers:
            receiver = self.receivers.popleft()
            ready(sender, None)
            run(receiver, obj)
        else:
            self.senders.append( (sender, obj) )

    def receive(self, receiver):
        ''' 从channel中接收数据,如果没用发送者,则让该tasklet等待'''
        if debuglevel:
            print 'tasklet:',receiver,'receive data ;senders:',len(self.senders)
        if self.senders:
            sender, obj = self.senders.popleft()
            ready(receiver,obj)
            run(sender, None)
        else:
            self.receivers.append(receiver)

class tasklet(object):
    '''http://www.stackless.com/wiki/Tasklets'''
    def __init__(self, func):
        self.func = func

    def __call__(self, *arg, **kw):
        '''将 genarator 加到就绪队列'''
        ready(self.func(*arg, **kw), None)

def run(task, obj):
    ''' 执行task '''
    try:
        result = task.send(obj)
    except StopIteration:
        pass
    else:
        if isinstance(result, command):
            # 给tasklet以执行 "系统命令" 的机会
            # 用户代码: yield command(func, ... )
            result(task)
        else:
            ready(task, None) # 加到就绪队列队尾,等待调度执行

def ready(task, obj):
    ''' 加入就绪队列 等待调度 '''
    readys.append( (task, obj) )

def schedule():
    ''' 调度就绪队列中的 tasklet '''
    while readys:
        task, obj = readys.popleft()
        run(task, obj)

# ============ test ===========

def simple_task(a):
    while True:
        print a
        yield None

def receiver(id, c):
    value = yield command(c.receive)
    print id,'receive', value
    while value:
        value = yield command(c.receive)
        print id,'received', value

def sender(id, c):
    value = 20
    while value:
        print id,'send',value
        yield command(c.send, value)
        value -= 1

def test_simple():
    tasklet(simple_task)(0)
    tasklet(simple_task)(10)
    tasklet(simple_task)(100)

def test_channel():
    c = channel()
    tasklet(receiver)('receiver1', c)
    tasklet(receiver)('receiver2', c)
    tasklet(sender)('sender1', c)
    c1 = channel()
    tasklet(receiver)('receiver3', c1)
    tasklet(sender)('sender2', c1)

if __name__=='__main__':
    #test_simple()
    test_channel()
    schedule()
}}}
哪个有权限就把这篇给删了吧,地址改到:
[:/HuangYi/yield stacklesspython:]

哪个有权限就把这篇给删了吧,地址改到: [:/HuangYi/yield stacklesspython:]

huangyi/2006-09-05 (last edited 2009-12-25 07:16:14 by localhost)