stackless
# 1. stackless 的安装和使用
stackless 在 python 库中没有默认包含,可以使用 pip 安装,但由于版本原因可能会安装失败。可以使用 pypy 版本的 python,pypy 默认集成了 stackless 库。 https://www.pypy.org/download.html 其他一些安装使用等,可以参照 github 上的说明 https://github.com/stackless-dev/stackless
stackless 可以理解为一个无栈的任务调度处理,那 stackless 就应该描述成一个无栈调用+协程调度。
# 2. stackless 的 hello world
import stackless
def fun(n):
print n
stackless.schedule()
print n
stackless.schedule()
stackless.tasklet(fun)(3)
stackless.tasklet(fun)(5)
stackless.run()
## 执行输出
# 3
# 5
# 3
# 5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
stackless 通过调用 run 函数启动,通过调用 tasklet 函数增加一个任务。在 stackless 启动后遇到 schedule 调用时当前任务将转向下一个可调用 tasklet 执行。在 stackless 内部会自动维护一个调度队列,以保证调度的顺序。
# 3. 看一个复杂点的例子
import stackless
channel = stackless.channel()
def producer():
print "producer started."
for i in range(5):
channel.send(i)
print "producer finished."
def consumer():
print "consumer start. "
while True:
data = channel.receive()
print "consumer data: " + str(data)
if data == 4:
break
print "consumer finished "
stackless.tasklet(producer)()
stackless.tasklet(consumer)()
stackless.run()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
这是一个生产者与消费者的例子,它使用 channel 在不同的 tasklet 间通信。当程序执行到 send 和 receive 时,会向 channel 写入消息,并且执行 schedule 调用。
# 4. 再看一个复杂点的例子
#-*- coding:utf-8 -*-
import stackless
import random
import sys
class hackysacker:
counter = 0
def __init__(self,name,circle):
self.name = name
self.circle = circle
circle.append(self)
self.channel = stackless.channel()
stackless.tasklet(self.messageLoop)()
def incrementCounter(self):
hackysacker.counter += 1
if hackysacker.counter >= turns: # 当循环到达限制,退出
while self.circle: # 向每个channel发送 exit
self.circle.pop().channel.send('exit')
def messageLoop(self):
while 1:
message = self.channel.receive() # 等待消息的到来
if message == 'exit':
return
debugPrint("%s got hackeysack from %s" % (self.name, message.name))
kickTo = self.circle[random.randint(0,len(self.circle)-1)]
while kickTo is self:
kickTo = self.circle[random.randint(0,len(self.circle)-1)]
debugPrint("%s kicking hackeysack to %s" % (self.name, kickTo.name))
self.incrementCounter()
kickTo.channel.send(self) # 向kickTo channel 发送消息,消息参数是self
def debugPrint(x):
if debug:print x
debug = 5
hackysackers = 5
turns = 1
def runit(hs=5,ts=5,dbg=1):
global hackysackers,turns,debug
hackysackers = hs
turns = ts
debug = dbg
hackysacker.counter = 0
circle = []
one = hackysacker('1',circle)
for i in range(hackysackers):
hackysacker(`i`,circle)
one.channel.send(one)
try:
stackless.run()
except TaskletExit:
pass
if __name__ == "__main__":
runit()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
例子来源于网络,该例中每个 hackysacker 会持有一个 tasklet,并且 hackysacker 对象会监听一个特定的 channel,所有的 tasklet 对象会存储在 circle 列表中,并且每个 tasklet 对象持有 circle 列表的引用。循环调用中,每个 tasklet 会随机选择一个 channel,向其发送消息。分片调度
编辑 (opens new window)
上次更新: 2023/02/24, 10:34:03