讲到这里,大家应该对“合作”有一点体会了。这里,每个任务都必须合作,也就是说必须能在较短的时间里将系统的控制权转交出去。如果某个任务进入了死循环,那么整个系统也就死了。
下面我们就来举一个用generator实现合作多任务的例子。假设这是一盘棋,电脑引擎和用户界面程序分别做成了generator。:
player = GetUserInput(...)
engine = Engine(...)
def game(red, black) :
...
move = red.next()
while move != Move.Resign :
if turn == black :
turn = red
else :
turn = black
game_state.update(move)
move = yield turn.send(move)
game_state.update(move)
这里能很清楚地看出generator所实现的合作多任务的单线程本质。因此如果我们的象棋引擎耍赖的话,:
def Engine() :
...
if game.LoseInevitable :
while 1 :
sleep(1000)
yield Move.Resign
那么你的程序就死了。
这是合作多任务的先天缺陷,因此在设计的时候你就得想好了,这个任务是不是适合用合作多任务来解决。
2. 异步I/O
coroutine的另一个用途是异步I/O。关于异步I/O,我曾经在邮件列表里写过 一封信 ,有兴趣的读者可以去看看。
在异步环境下,你把一堆socket交给监听器。监听器则负责告诉你socket是不是可读可写。监听器只能帮你把数据读出来,至于读出来的东西是不是合法,该怎么用,它就无能为力了。因此你得写一大堆回调函数,让监听器帮你把信息分发到回调函数里。
这个任务可不容易。因为监听器是根据收到的信息来判断调用哪个回调函数的,但是函数却不一定知道该怎么处理这个信息。比方说,监听器听到用户输入了一个PASS命令,于是调用do_PASS。但是这个口令是谁的,或者用户先前有没有使用USER命令,监听器都不知道。既然监听器不知道,do_PASS也就无从获知,因此回调函数里面还有一大堆麻烦事等着。
有了coroutine之后,我们可以将每个会话封装成一个generator。当监听器听到数据的时候,可以用send方法,把信息传给coroutine,让coroutine继续运行,等yield完值之后再睡。coroutine的这种工作方式与线程很相似,因此也被称作pseudo-thread。
下面我们举一个完整的例子。程序清单如下:
1 #!/usr/local/bin/python2.5
2
3 import socket, select, collections
4
5 SOCK_TIMEOUT = 0.1
6 BUFSIZ = 8192
7 PORT = 10000
8
9 def get_auth_config() :
| 论坛热门帖子: | [lch203] 写得蛮好的linux学习笔记(10-21) [黑马制造] 学习java的30个目标(10-19) [笑傲股林] 做测试半年了,有点迷茫,应该再学些什么提高自己的测试水平和测试能力呢?(10-19) [udp8589] 大家用google的来吱一声? 用百度的~~也来报道下?(10-18) [沂偌掳兆] 本人总结的一些认为C++比较经典的书籍,希望对大家有用(10-18) |
| TAG标签: | generator 任务 一个 yield 合作 可以 coroutine 我们 |
注册
个人空间
