#关于Python里面协程的一些理解
Python关于协程是有点难理解的,但其实就协程的定义来说其实并不难。
协程,又称微线程,纤程。英文名Coroutine
协程和多线程以及多进程都不一样,协程有极高的执行效率。
因为子程序切换不是线程切换,而是由程序自身控制,
因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显。
Python对协程的支持是通过生成器(generator)实现的。
所谓生成器,也是一种可迭代对象,通常创建生成器有两种方式
1、如:g = (x*x for x in range(5))
print(g)=====><generator object <genexpr> at 0x0000000002A3CFC0>
即g是一个生成器对象
操作g有两种方式:
①next()方法:next(g)==>0 next(g)==>1 next(g)==>4 next(g)==>9 next(g)==>16
②for循环(上面说到了生成器是可以迭代的):
for i in g:
print(i)
输出是:0 1 4 9 16
2、函数里面包含关键字yield就成了生成器
如:def A():
for i in range(3):
yield i
这里值得注意的是它与一般函数执行过程不大一样,遇到yield就返回,
它返回的不是具体的值而是一种状态值,然后下一次从yield下面的代码开始执行
操作A也是两种,一种next一种for循环。
需要注意下下面的代码:
>>> def a():
... yield 3
...
>>> a()
<generator object a at 0x0000000002A3CF68>
>>> type(a)
<class 'function'> 可以看到这里a还是方法
>>> type(a()) 但是a()是生成器
<class 'generator'>
了解了生成器后便来聊聊协程吧,我们通过一个例子来理解:
传统的生产者-消费者模型是一个线程写消息,一个线程取消息,
通过锁机制控制队列和等待,但一不小心就可能死锁。
如果改用协程,生产者生产消息后,直接通过yield跳转到消费者开始执行,
待消费者执行完毕后,切换回生产者继续生产,效率极高:
def consumer():
r = ''
while True:
n = yield r
if not n:
return
print('consumer %s' %n)
r = '886'
def produce(c):
c.send(None)
i = 0
while i < 5:
i = i+1
print('produce %s' %i)
m = c.send(i)
print('consumer66660 %s' %m)
c.close()
c = consumer()
produce(c)
输出结果:
produce 1
consumer 1
consumer66660 886
produce 2
consumer 2
consumer66660 886
produce 3
consumer 3
consumer66660 886
produce 4
consumer 4
consumer66660 886
produce 5
consumer 5
consumer66660 886
上面这段代码,consumer是一个生成器,而produce函数传入的参数是一个生成器对象。
代码的具体执行顺序是最需要弄明白的
具体流程:
1、首先c = consumer()创建了一个生成器对象c
注意这里创建生成器对象c的时候,并没有去执行consumer内部的代码,
就比如下面这段代码:
>>> def A():
... for i in range(7):
... print(666)
... yield i
...
>>> n = A()
>>> next(n)
666
0
可以看到创建n的时候并没有打印出666,证明没有执行内部代码。
2、然后执行produce(c)函数,这里首先执行c.send(None),这个send(None)方法相当于启动了生成器consumer
注意这里send(None)参数必须是None,
因为send函数是将参数赋值给类似consumer里面的n = yield r 中的n的,
而这里根本还没有n存在,你如果传个非空的参数进去就会报错。
3、然后转而执行consumer内代码,首先r=‘’,然后进入while循环,执行到n = yield r句的时候我们要特别注意:
其实这行代码包含了三个意思:
①向函数外抛出(返回)r
②暂停,等待next()或send()恢复
③赋值,n接收send(m)发送进来的m
这样对应起来,此时执行到这里,向函数外抛出r(这里但是并没有谁去接收这个r)之后,然后函数暂停。
4、转而执行produce()里的语句i = 0,然后继续向下执行,到print('produce %s' %i)语句
打印出第一条输出:produce 1。
5、继续向下执行遇到 m = c.send(i),再次切换到consumer内执行,
这里切换过去后要注意,是从n = yield r语句的第③步开始的,
即将m = c.send(i)(此时i为1)的i传给了n = yield r里面的n(所以此时n为1)
6、继续向下执行consumer里面的代码,if not n 判断条件 not n为false,跳过if语句
执行print('consumer %s' %n),输出consumer 1,然后r = ‘886‘,然后继续while循环
又遇到n = yield r,此时抛出的r,然后暂停。
注意:这个抛出的r(已经变为886)被produce内m = c.send(i)的m接受了于是m=’886‘
7、然后执行print('consumer66660 %s' %m) 输出:consumer66660 886
至此,有了前三行输出:
produce 1
consumer 1
consumer66660 886
8、然后进入produce里面第二次while循环,流程跟上面一样,不再赘述。
以上,不足之处请多多指教,Thanks~!
关于Python里面协程的一些理解
最新推荐文章于 2024-04-24 16:12:48 发布