一文看懂Python中的协程

1. 什么是协程

在 Python 和 Lua 语言中,都有协程这个概念,那么什么是协程呢?

协程是单线程下的并发,又称微线程,纤程。英文名Coroutine。

一句话总结:协程是一种用户态的轻量级线程,即协程是由用户程序自己控制调度的。

也就是说它和程序员有关系,相对线程和进程来说,调度是由CPU来决定调度的。

2. 协程出现的原因

Python 由于众所周知的 GIL 的原因,导致其线程无法发挥多核的并行计算能力。

在GIL之下,同一时刻只能有一个线程在运行,在多任务并发(非并行)的情况下,每个任务在合适的时候挂起(发起I/O)和恢复(I/O结束),这样可以极大的提高CPU的效率。

相对而言,如果是cpu密集型,推荐多进程的方式。

在早期的 Python 实现中,是通过 yieldsend 来分别实现切换,及返回结果。

举例来说:

import random
import time

def stupid_fib(n):
    index = 0 
    a = 0 
    b = 1 
    while index < n:
        sleep_cnt = yield b
        print('query https://www.xtuz.net {0} secs'.format(sleep_cnt))
        time.sleep(sleep_cnt)
        a, b = b, a + b 
        index += 1
print('-'*10 + 'test yield send' + '-'*10)
N = 20
sfib = stupid_fib(N)
fib_res = next(sfib)
while True:
    print(fib_res)
    try:
        ss = random.uniform(0, 0.5)
        print('ss=%s' %ss)
        fib_res = sfib.send(ss)
    except StopIteration:
        break

yield - 用来从子程序中断,并返回结果

send - 用来从主程序向子程序发送信息

2. 协程的优缺点

协程优点主要有以下两点:

  1. 协程的切换开销更小,属于程序级别的切换,操作系统完全感知不到,因而更加轻量级
  2. 单线程内就可以实现并发的效果,最大限度地利用 CPU

协程缺点主要也有以下两点

  1. 协程的本质是单线程下,无法利用多核,可以是一个程序开启多个进程,每个进程内开启多个线程,每个线程内开启协程
  2. 协程指的是单个线程,因而一旦协程出现阻塞,将会阻塞整个线程

4. 协程的使用场景

协程基于generator,Python3 中内置了异步IO。遇到IO密集型的业务时,总是很费时间啦,多线程加上协程, 在磁盘在读写的同时,还能去做其他的事情,在WEB应用中效果尤为明显。


相关主题: