本文对python协程做一些总结,来自平时的学习和一些博客资料
1. 异步IO
关于异步IO的讲解,网上资料太多了,我以前的文章也提到过,此处只做一些简单介绍:
- 异步IO采用消息循环的模式,重复“读取消息—处理消息”的过程
- 消息模型解决等待IO操作的问题:
- 程序发出IO请求,直接结束本轮消息处理,进入下一轮消息的处理
- 当IO操作完成守,将收到一条IO完成的消息,处理该消息时获取IO操作的结果
- 在IO操作的这段时间里,异步模型可以循环处理其他操作,而且没有线程切换的消耗,同时处理多个IO请求,适用于大多数IO密集型的应用程序。
python 的异步协程 (async coroutine) ,在提交 HTTP 请求后,就没必要等待请求完成再进一步操作,而是可以一边等着请求完成,一边做着其他工作。这可能在逻辑上需要多些思考来保证程序正确运行,但是好处是可以利用更少的资源做更多的事。
2. 协程概念
协程是python异步IO中常用的一个概率,英文为coroutine。协程不同于进程和线程,在某种程度上,它的概念更接近于函数调用的概念。
2.1 函数调用:
我们知道,程序执行中,函数调用是通过函数栈实现,因为栈FILO的特点,通常函数调用过程都是:A调用B,B在执行过程中又调用了C,C执行完毕返回,B执行完毕返回,最后是A执行完毕。子程序(函数)调用总是一个入口,一次返回,调用顺序是明确的。而协程的调用和子程序不同。
2.1 协程调用:
协程和函数最相似的地方就是协程本身的定义就更函数很像,而其调用也很相像。
协程看上去也是子程序,但执行过程中,在子程序内部可中断,然后转而执行别的子程序,在适当的时候再返回来接着执行。
协程针对的是一个线程中的函数调用之间,所以没有线程切换,是在一个线程中轮流执行和终端多个函数而已,所以效率较高,而且不需要锁机制(只有一个线程执行)
需要注意的是,子程序内部中断的不是函数调用,而是被调用函数中断(一般来说可能是一条执行命令需要很长时间等待结果返回,比如常见的IO操作),转而去执行另一个函数(不是调用另一个函数),类似两个函数轮流执行,没有发生函数调用。
上述的执行流程看上去很像多线程有木有!!!实际上,一些协程的执行结果也很像多线程的执行结果,因为本质就是不同代码段轮流执行,进而提高效率。协程得到运用主要在于其效率更高:
协程的执行效率较高,因为不是线程切换,而是程序控制,没有开销。因为是一个线程中有多个协程,所以不需要锁机制。
此外,多线程编程中锁机制的开销在协程中也不存在,因为协程不需要锁机制:
因为协程执行是在一个线程中,不存在同时写变量冲突,所以共享资源不需要加锁,只需要判断状态就好,进一步提升效率。
3. python中的协程操作
python中协程的支持是通过生成器(generator)实现的。
熟悉generator的知道:函数定义时,将函数的结果通过yield返回,则定义了一个生成器,而在生成器中,我们不但可以通过for循环来迭代,还可以不断调用next()函数获取由yield语句返回的下一个值。
而对于协程来说,yield不但可以返回一个值,它还能接收函数调用者发出的参数。(这句话很重要)
下面运用网上教程讲解的一个例子(我觉的很清晰)来说明协程操作:
传统的生产者-消费者模型是一个线程写消息,一个线程取消息,通过锁机制控制队列和等待,但一不小心就可能死锁。如果改用协程,生产者生产消息后,直接通过yield跳转到消费者开始执行,待消费者执行完毕后,切换回生产者继续生产,效率极高:
代码如下: