您的位置:首页 > 编程语言 > Python开发

增强型的 yield 大致模拟了下 StacklessPython 的 api

2008-10-13 18:00 288 查看
主要是因为相对 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 才能将执行权切换给调度程序,像下面:

def a_task():
a_func()
def a_func():
# 在这个函数里是没用办法将执行权切换给调度程序的。
不像 StacklessPython ,随便哪里调用 stackless.schedule() 都可以把执行权交出去。

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

#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()
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: