|
| 1 | +## python中的协程 |
| 2 | +**协程是一种比线程更加轻量级的存在,最重要的是,协程不被操作系统内核管理,协程是完全由程序控制的。** |
| 3 | +* 运行效率极高,协程的切换完全由程序控制,不像线程切换需要花费操作系统的开销,,线程数量越多,协程的优势就越明显。 |
| 4 | +* 协程不需要多线程的锁机制,因为只有一个线程,不存在变量冲突。 |
| 5 | +* 对于多核CPU,利用多进程+协程的方式,能充分利用CPU,获得极高的性能。 |
| 6 | + |
| 7 | +#### 1.一个简单的协程 |
| 8 | + |
| 9 | +```python |
| 10 | +def simple_coroutine(): |
| 11 | + print('coroutine start...') |
| 12 | + x = yield |
| 13 | + print('receive x = {}'.format(x)) |
| 14 | + y = yield |
| 15 | + print('receive y = {}'.format(y)) |
| 16 | + |
| 17 | + |
| 18 | +if __name__ == '__main__': |
| 19 | + # 1. 调用协程函数,函数并不执行,而是返回一个生成器(协程对象) |
| 20 | + # <generator object simple_coroutine at 0x0000023E051A2360> |
| 21 | + coro = simple_coroutine() |
| 22 | + print(coro) |
| 23 | + # 2. 预激协程,激活协程,程序在下一个yield处停止,等待接收数据 |
| 24 | + next(coro) |
| 25 | + # 3. 给协程发送数据 |
| 26 | + coro.send(10) |
| 27 | + coro.send(20) |
| 28 | + # 4. 控制权流动到协程定义体的末尾,导致生成器像往常一样抛出StopIteration异常。 |
| 29 | +``` |
| 30 | +运行结果 |
| 31 | +```python |
| 32 | +<generator object simple_coroutine at 0x000001C8604323B8> |
| 33 | +coroutine start... |
| 34 | +receive x = 10 |
| 35 | +receive y = 20 |
| 36 | +Traceback (most recent call last): |
| 37 | + File "E:/code/web_request/fluent_python/fluent_python_4.py", line 21, in <module> |
| 38 | + coro.send(20) |
| 39 | +StopIteration |
| 40 | +``` |
| 41 | + |
| 42 | +#### 2.协程的状态 |
| 43 | +通过 inspect.getgeneratorstate(my_corou) 查看协程的4种状态<br> |
| 44 | +1. GEN_CREATED :等待开始执行 |
| 45 | +2. GEN_RUNNING :解释器正在执行 |
| 46 | +3. GEN_SUSPENDED :在yield表达式处暂停 |
| 47 | +4. GEN_CLOSED :执行结束 |
| 48 | + |
| 49 | +```python |
| 50 | +from inspect import getgeneratorstate |
| 51 | + |
| 52 | +def simple_coroutine(): |
| 53 | + print('coroutine start...') |
| 54 | + x = yield |
| 55 | + print('receive x = {}'.format(x)) |
| 56 | + y = yield |
| 57 | + print('receive y = {}'.format(y)) |
| 58 | + |
| 59 | +if __name__ == '__main__': |
| 60 | + coro = simple_coroutine() |
| 61 | + print(getgeneratorstate(coro)) # 被创建 GEN_CREATED |
| 62 | + next(coro) |
| 63 | + print(getgeneratorstate(coro)) # 在yield表达式处暂停 GEN_SUSPENDED |
| 64 | + coro.send(10) |
| 65 | + try: |
| 66 | + coro.send(20) |
| 67 | + except StopIteration: |
| 68 | + print('coroutine end...') |
| 69 | + print(getgeneratorstate(coro)) # 协程执行结束 GEN_CLOSED |
| 70 | +``` |
| 71 | + |
| 72 | +#### 3.yield关键字 |
| 73 | +yield可以看做是流程控制工具,主要是产出和让步两个作用。 |
| 74 | +1. yield关键字会产生出返回值给协程的调用者 |
| 75 | +2. yield关键字会做出让步,暂停执行,把控制器让步给中心调度程序(调用者)。 |
| 76 | + |
| 77 | +主要理解yield的两个作用: |
| 78 | +```python |
| 79 | +b = yield a 可以看成两步: |
| 80 | +1. return a # 返回yield右边的表达式 |
| 81 | +2. b = yield # 暂停协程,等待接收数据 |
| 82 | +``` |
| 83 | + |
| 84 | +```python |
| 85 | +def simple_coroutine2(a): |
| 86 | + print('coroutine start...') |
| 87 | + b = yield a |
| 88 | + print('receive b = {}'.format(b)) |
| 89 | + c = yield b |
| 90 | + print('receive c = {}'.format(c)) |
| 91 | + |
| 92 | + |
| 93 | +if __name__ == '__main__': |
| 94 | + coro = simple_coroutine2(5) |
| 95 | + a = next(coro) |
| 96 | + print('a = {}'.format(a)) |
| 97 | + print('此时协程做出让步,暂停了,主程序继续向下执行....') |
| 98 | + b = coro.send(10) |
| 99 | + try: |
| 100 | + c = coro.send(20) |
| 101 | + except StopIteration: |
| 102 | + print('coroutine end...') |
| 103 | +``` |
| 104 | +运行结果 |
| 105 | +```python |
| 106 | +coroutine start... |
| 107 | +a = 5 |
| 108 | +此时协程做出让步,暂停了,主程序继续向下执行.... |
| 109 | +receive b = 10 |
| 110 | +receive c = 20 |
| 111 | +coroutine end... |
| 112 | +``` |
0 commit comments