1.协程的概念:
子程序或者子函数,在所有语言中都是层级调用,比如A调用B,再B执行的过程中又可以调用C,C执行完毕返回,B执行返回,最后是A执行完毕返回。是通过栈来实现的,一个线程就是执行一个自称,自称调用时一个入口,一次返回,调用的顺序是明确的。
代码:
def C(): print("C--Start") print("C--end") def B(): print("B--Start") C() print("B--end") def A(): print("A--Start") B() print("A--end") A() # A--Start # B--Start # C--Start # C--end # B--end # A--end
协程:看上去也是子程序,但是在执行过程中,在子程序内部可以中断。中断然后转而执行别的子程序,而不函数调用。
协程与线程相比,协程的执行效率极高,因为只有一个线程,也不存在同时写变量的冲突,在协程中通向资源不加锁,只需要判断状态就可以了。比如如下的代码,可以如何处理?
def A(): print(1) print(2) print(3) def B(): print("x") print("y") print("z") # 执行这个结果而不用A调用B # 1 2 x y z 3 # 看起来A、B执行过程有点儿像线程,但协程特点在于是一个线程执行
2. 建立一个简单的协程:
协程是通过generator来实现的。
先上代码:
def run(): print(1) yield 10 print(2) yield 20 print(3) yield 30 # 协程的最简单风格,控制函数的阶段执行,节约线程或者进程的切换。 # 返回值是一个生成器。 m = run() print(next(m))
说明:其实我们这里使用了一个生成器的概念。触发一个生成器,让生成器不断去执行。
说明:yield = return,这两个的字面意思是一样的,但是yield的返回不是直接返回,而是等待用户操作,让其返回到么偶一个位置。
3. 数据传输:
代码:
def run(): # 空变量,存储的作用data始终未空 data = "" r = yield data # r = a print(1,r,data) r = yield data # r= b print(2,r,data) r = yield data # r = c print(3,r,data) r = yield data m = run() # 等于制作了一个生成器 # 启动m print(m.send(None)) print(m.send("a")) print(m.send("b")) print(m.send("c")) # 注意这里是一个空值打印 # 1 a # # 2 b # # 3 c
说明1:.send()是发送信息给生成器。
说明2:运行过程如下:(注意我们要把yield看做return就好理解了)
第一步:先给函数发送一个None空值,接到到空值之后,yield返回data的空值给r,打印空。
第二部分:我们给data发送一个“a”,然后yield返回data的“a”值给r,打印1,“a”
后面类似。
举例:我们用一个函数的形式把生成器传递给参数。
def producer(c): c.send(None) for i in range(5): print("生产者产生数据%d" %i) r = c.send(str(i)) print("消费者消费了数据%s" %r) c.close() def customer(): data = "" while True: n = yield data if not n: return print("消费者消费了%s" % n) data = "200" c = customer() producer(c) # 生产者产生数据0 # 消费者消费了0 # 消费者消费了数据200 # 生产者产生数据1 # 消费者消费了1 # 消费者消费了数据200 # 生产者产生数据2 # 消费者消费了2 # 消费者消费了数据200 # 生产者产生数据3 # 消费者消费了3 # 消费者消费了数据200 # 生产者产生数据4 # 消费者消费了4 # 消费者消费了数据200