点击关注了解更多精彩内容!!
今天介绍下协程的概念,文末会对整篇做一个总结,了解总结的几点,也就大致理解了协程的用法。
全方位了解协程概念
协程:实现协作式多任务,可以在程序执行内部中断,转而执行其他协程。
比如我们编写子程序(或者说函数),通常是利用“调用”来实现从 A 跳去 B,B 跳去 C,如果想回来调用方,必须等被调用方执行完才行,整个调用过程是通过栈实现的。而协程是运行子程序的过程中“中断”,转而执行其他子程序,再在适当的时候返回来接着运行。
协程相比于线程的优势: 1、协程效率比线程高。线程间切换需要开销,而协程间切换是由程序自身控制的,不需要开销。 2、协程不需要多线程的锁机制。协程是在一个线程内进行切换,所以不存在同时写变量冲突,不需要给共享资源加锁,只需要判断状态。
PS:如果想使用多CPU的话,可以使用进程+协程。
协程是通过yield实现的,所以协程是生成器,可以通过 next 调用。
def simple(a):
print("----start----")
r = yield a
print('----r------' + str(r))
>>> my_simple = simple(5)
>>> my_simple
<generator object simple at 0x10f9242b0>
>>> next(my_simple)
----start----
5
>>> my_simple.send(8)
----r------8
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
以上是一个简单的协程例子,可以看到,my_simple是一个生成器实例,需要使用next()方法或send(None)去预激协程,协程运行到yield的时候停止,当使用send()方法给yield赋值时,程序继续往下运行,并抛出StopIteration异常。
在python3.3版本后,协程可以有返回值。
def simple(a):
print("----start----")
r = yield a
print('----r------' + str(r))
return r
>>> my_simple = simple(5)
>>> next(my_simple)
----start----
5
>>> my_simple.send(8)
----r------8
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration: 8
可以看到,在程序运行完后,异常对象StopIteration的value属性保存着返回的值。
对于yield from来说,解释器不仅会捕获StopIteration异常,还会把value属性的值作为yield from表达式的值。
yield from主要功能是打开双向通道,把最外层的调用方和最内层的子生成器连接起来。
# 子生成器
def total_num():
total = 0
while True:
num = yield
if num == None:
break
total += num
return total
# 委派生成器
def send_num(result, key):
while True:
result[key] = yield from total_num()
# 调用方
def main(data):
result = {}
for key, nums in data.items():
group = send_num(result, key)
next(group)
for num in nums:
group.send(num)
group.send(None)
print(result)
data = {
'nums1': [12, 34, 23, 4, 35, 34, 34, 55],
'nums2': [22, 44, 33, 24, 33, 24, 4, 15],
'nums3': [32, 54, 43, 41, 31, 44, 24, 25],
'nums4': [42, 64, 53, 43, 37, 74, 74, 35],
'nums5': [52, 74, 63, 46, 39, 84, 44, 45]
}
if __name__ == "__main__":
main(data)
输出结果如下:
{'nums1': 231, 'nums2': 199, 'nums3': 294, 'nums4': 422, 'nums5': 447}
委派生成器作为双向管道把调用方和子生成器连接起来,委派生成器在yield from表达式处暂停时,调用方通过send()方法把数据传给子生成器,子生成器再把产出值发送给调用方,子生成器返回后,会抛出StopIteration异常,并把返回值添加到异常的value属性上,此时你异常生成器会恢复,并获取异常的value值作为yield from表达式的值。
委派生成器相当于管道,所以可以把任意个委派生成器连起来:委派生成器连接的子生成器是一个委派生成器,以此类推,直到遇到一个使用yield的生成器或可迭代对象。
1、协程是用于控制程序中断,它与函数调用不同
2、协程是在单线程里可处理多任务,相比多线程节省了线程切换的开销
3、协程通过 yield 关键字实现,它也是一种生成器
4、协程调用方可通过 send() 方法给被调用方发送值。协程的开启需要预激,预激方法是:send(None)或者next()
5、协程在 python3.3 之后是有返回值的,返回值会放在 StopIteration 异常的 value 里
6、yield from 的作用是在生成器里调用子生成器,可以优化一个嵌套 for 循环等复杂代码
7、协程有四种状态:GEN_CREATED(等待开始执行)、GEN_RUNNING(解释器正在执行)、GEN_SUSPENDED(在yield表达式处停止)、GEN_CLOSED(执行结束)。通过 inspect.getgeneratorstate(…) 函数可获取
8、结束协程的两种方式:generator.throw 或 generator.close
你点的每个赞,我都认真当成了喜欢