python 从yield 到 async/await

作者 Yingying Zheng 日期 2017-08-27
python 从yield 到 async/await

闲来无事研究下python3 的新特性 发现一个挺有意思的东西,协程(coroutine);

协程,可以理解为自身控制切换的线程,即不用GIL来控制子程序切换,用自身代码控制;相对于线程来说减少了线程切换的开销;
协程中控制共享资源不加锁,只要使用代码判断状态就好了。网上另一种解释也说,协程就是你可以暂停执行的函数,像生成器一样。

最近开始接触协程,了解到他是从yield发展来的,从头开始看下,and 记录下;

yield

在python中 带有 yield 的函数 被称为生成器(generator);

带有yield 函数在调用的时候不会被直接执行,而是返回一个迭代对象,在for 循环中调用,循环时 会执行函数中的内容,当遇到yield时返回,当下次再执行时,会从yield下一句开始执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def foo():
current = 0
while current < 1000:
yield current
current += 1
print foo()
1
2
[root@bogon walleui_db]# python test.py
<generator object foo at 0x7fc7d0c9e1e0>

由此可见,yield把一个函数改写为一个 generator 就获得了迭代能力,
比起用类的实例保存状态来计算下一个 next() 的值,不仅代码简洁,而且执行流程异常清晰。

yield 引入send

单纯的yield 只能实现 从 方法内部流向 外面,而无法注入参数到方法里(此处的方法指的是有yield的生成器)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def foo1(max_count):
current = 0
send_param = 0
while current < max_count:
cnt = yield send_param
print cnt
current += 1
tt = foo1(20)
t_obj = next(tt) #让程序运行到第一个yield处
while True:
try:
tt.send(3)
except StopIteration:
break

注意:此处的send 传递的参数传递给了send_param, 也就是cnt,并不是max_count,传统的思想导致这里误区很大

接下来是 yield from

Python 3.3 添加了 yield from,yield form 说是重构生成器,不是太理解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
def foo(max_count):
current = 0
send_param = 0
while current < max_count:
cnt = yield send_param
print(cnt)
current += 1
#
# tt = foo1(20)
# t_obj = next(tt) #让程序运行到第一个yield处
#
# while True:
# try:
# tt.send(3)
# except StopIteration:
# break
#
def copy_foo(n):
print("copy_foo")
yield from foo(n)
print("after foo")
tt = copy_foo(22)
res = next(tt)
while True:
try:
tt.send(3)
except StopIteration:
print("over")
break

注意:这里必须使用python3.3以上

yield from 可以像一个管道一样将send信息传递给内层协程

本人理解类似于类的继承,这里实现了协程的继承

@asyncio.coroutine

Python 3.4 中,asyncio.coroutine 修饰器用来标记作为协程的函数,
这里的协程是和asyncio及其事件循环一起使用的,通过yield from,我们可以将协程asyncio.sleep的控制权交给事件循环,然后挂起当前协程;

async和await

Python3.5中引入的async和await 替代 asyncio.coroutine/yield from

接下来装完环境继续研究

每次写博客都是一次头脑风暴,获益颇多!!!!