python 自身的协程实现?

本来,想给这个随笔起个更眩的名字:《跟随赖神学协程——之一》,原因嘛,自然是因为赖神的协程三篇之一(协程初接触)。不过,怕赖神k我,所以标题党还是朴素一点吧。

至于标题里的问号,是我有意加上去的。原因是在推上赖神认为“python 语言和标准库是不支持协程的(3.x部分支持)”,并且如果 python 自身支持协程,“stackless py 该有多么惭愧啊, :)”(stackless python 的协程详情请看这里)。但是因为 PEP 0342 的描述,令我很迷惑。python 自身是否可以实现协程,这个值得商榷。我不确定,保守点好,给自己个后路走。加个问号吧……如果这不算协程,大家就当我实现了“伪协程”吧。嘿嘿……

在赖神的博客里有对协程的一个简单的描述,为了说明下面的代码,特别摘抄于此:“协程是用户空间线程,操作系统其存在一无所知,所以需要用户自己去做调度,用来执行协作式多任务非常合适。”

赖神博客中的例子应当是引用了维基百科对于协程的说明。下面的代码正是基于这个伪代码实现的,同样的原因摘抄于此:
生产者:

<br />
   loop<br />
       while q is not full<br />
           create some new items<br />
           add the items to q<br />
       yield to consume<br />

消费者
<br />
   loop<br />
       while q is not empty<br />
           remove some items from q<br />
           use the items<br />
       yield to produce<br />

这两段伪代码,赖神的博客上已经有说明,不再累述。看看 python 如何实现这个的吧:
<br />
#!/usr/bin/evn python<br />
# -*- coding:utf-8 -*-<br />
import time<br />
# 生产者<br />
def produce(l):<br />
	i = 0<br />
	while True:<br />
		i += 1<br />
		l.append(i)<br />
		time.sleep(2)<br />
		# 暂时跳出当前方法<br />
		yield i<br />
		# 消费者 send 了以后,就又回到了这里继续执行<br />
		pass</p>
<p># 消费者<br />
def consume(l):<br />
	p = produce(l)<br />
	while True:<br />
		try:<br />
			# 获取生产者的执行<br />
			i = p.next()<br />
			# 这里完全是为了匹配伪代码而写,实际上这个 list 在这种情况下,即不会多于一个 item,也不会为空<br />
			while len(l) &gt; 0:<br />
				print l.pop()<br />
		except:<br />
			# 生产者提供的所有的执行都处理完了,通过 send 返回生产者跳出的地方<br />
			p.send(None)<br />
l = []<br />
consume(l)<br />

这段代码是可以正常执行的,由生产者每秒产生一个数字放入 list,由消费者从 list 中取出并打印。
大家对照赖神的说明和维基百科上的内容理解一下吧。

总结一下!我对于 python 的协程的观点是:“python 自身已经提供了实现协程的基础条件,是可以很容易的实现概念中的协程。但是由于栈的问题,只能由循环的方式来实现调用。而 stackless 在 python 原有的基础上,改进了 python 在协程上的实现方式,使其代码的表达更加的自然。”

如有不对,尽请拍砖,期待赖神的协程系列二、三。继续品味协程……

2 thoughts on “python 自身的协程实现?”

  1. 我觉得这个例子并没有很好的展示generator或者是yield的功能。
    你这样个例子完全可以在一个函数里面来实现,没有必要使用generator,generator的一个重要的功能就是:它具有记忆能力,可以从上次执行的地方继续执行。
    我觉得如果你的例子中的消费者或者是生产者如果函数如果在yield之后作的功能需要依赖于yield之前的功能的话,那就能很好的展现generator的功能了

Leave a Reply

Your email address will not be published. Required fields are marked *