⇤ ← Revision 1 as of 2006-09-05 08:04:51
Size: 4338
Comment: 使用 python2.5 增强的 yield 大致模拟 StacklessPython 的 api。
|
Size: 4522
Comment:
|
Deletions are marked like this. | Additions are marked like this. |
Line 22: | Line 22: |
本来还想把 ["evolution"] 也转过来的,发现 pygame 还没为 windows 编译 python2.5 的版本,自己编译太麻烦,还是等 python2.5 正式发布了再说吧。 |
["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 才能将执行权切换给调度程序,像下面:
不像 StacklessPython ,随便哪里调用 stackless.schedule() 都可以把执行权交出去。
谁叫人家c写的呢。:(
本来还想把 ["evolution"] 也转过来的,发现 pygame 还没为 windows 编译 python2.5 的版本,自己编译太麻烦,还是等 python2.5 正式发布了再说吧。
- 注意:运行下面程序需要 python2.5
1 #coding:utf-8
2 from collections import deque
3
4 '''
5 http://www.stackless.com/
6 '''
7
8 debuglevel = 0
9
10 readys = deque() # 就绪队列
11
12 class command(object):
13 def __init__(self, func, *args, **kw):
14 self.func = func
15 self.args = args
16 self.kw = kw
17
18 def __call__(self, task):
19 return self.func(task, *self.args, **self.kw)
20
21 class channel(object):
22 ''' http://www.stackless.com/wiki/Channels '''
23 def __init__(self):
24 self.senders = deque() # 发送队列 元素:(tasklet, obj)
25 self.receivers = deque() # 接收队列 元素:tasklet
26
27 def send(self, sender, obj):
28 '''向channel中发送数据,如果没用接受者,则让该tasklet等待'''
29 if debuglevel:
30 print 'tasklet:',sender,'send data:',obj,';receivers:',len(self.receivers)
31 if self.receivers:
32 receiver = self.receivers.popleft()
33 ready(sender, None)
34 run(receiver, obj)
35 else:
36 self.senders.append( (sender, obj) )
37
38 def receive(self, receiver):
39 ''' 从channel中接收数据,如果没用发送者,则让该tasklet等待'''
40 if debuglevel:
41 print 'tasklet:',receiver,'receive data ;senders:',len(self.senders)
42 if self.senders:
43 sender, obj = self.senders.popleft()
44 ready(receiver,obj)
45 run(sender, None)
46 else:
47 self.receivers.append(receiver)
48
49 class tasklet(object):
50 '''http://www.stackless.com/wiki/Tasklets'''
51 def __init__(self, func):
52 self.func = func
53
54 def __call__(self, *arg, **kw):
55 ready(self.func(*arg, **kw), None)
56
57 def run(task, obj):
58 ''' 执行task '''
59 try:
60 result = task.send(obj)
61 except StopIteration:
62 pass
63 else:
64 if isinstance(result, command): # 给tasklet以执行 "系统命令" 的机会
65 result(task)
66 else:
67 ready(task, None)
68
69 def ready(task, obj):
70 ''' 加入就绪队列 等待调度 '''
71 readys.append( (task, obj) )
72
73 def schedule():
74 ''' 调度就绪队列中的 tasklet '''
75 while readys:
76 task, obj = readys.popleft()
77 run(task, obj)
78
79 # ============ test ===========
80
81 def simple_task(a):
82 while True:
83 print a
84 yield None
85
86 def receiver(id, c):
87 value = yield command(c.receive)
88 print id,'receive', value
89 while value:
90 value = yield command(c.receive)
91 print id,'received', value
92
93 def sender(id, c):
94 value = 20
95 while value:
96 print id,'send',value
97 yield command(c.send, value)
98 value -= 1
99
100 def test_simple():
101 tasklet(simple_task)(0)
102 tasklet(simple_task)(10)
103 tasklet(simple_task)(100)
104
105 def test_channel():
106 c = channel()
107 tasklet(receiver)('receiver1', c)
108 tasklet(receiver)('receiver2', c)
109 tasklet(sender)('sender1', c)
110
111 if __name__=='__main__':
112 #test_simple()
113 test_channel()
114 schedule()