协程是python中除了进程和线程之外又一种能够实现多任务的方式,又称为微线程,纤程,它相比于线程需要的资源更少。
在python种协程是通过generator实现的。通过yield保存当前运行的状态然后切换到另一个协程执行。普通的生产者-消费这模式是一个线程写消息,一个线程才能读取消息,因此需要控制队列的写入与读取数据。而改用协程可以在生产者生产消息后直接通过yield跳转到消费者开始执行,执行完毕后在切换到生产者,如此反复,效率极高。
在图中,我们可以看出通过next的方法使得生成器中的任务完成了交替执行,实现了多任务。
注意,在协程模拟中,相较于线程没法设计运行顺序,协程是可以设计执行的顺序的。这样协程之间就能协作完成任务,而不会如线程一样得抢占资源。
由于协程得切换只是简单得操作CPU得上下文,因此系统甚至在1s中切换几百万次都毫无压力。
在python中为了更好得使用协程来完成任务,可以使用python中greenlet模块和gevent。greenlet在协程切换需要人工切换,因此主要给大家介绍gevent这个强大且能自动切换任务的模块。
在讲解gevent模块直接,大家需要先了解一下协程主要发力的领域,那就是异步IO。
我们都知道CPU得执行速度很快,每秒几百万次几千万次得速度小菜一碟。在IO操作得时候,如读写文件,发送网络数据等,都需要等待IO操作才能执行下面的代码,这种情况就叫做同步IO。在IO操作得过程中,当前的线程是被挂起的,下面的代码需要等待IO操作完成才能执行。如网络通信send数据,和recv数据得过程实际上都在等待服务器回应。这个时候就需要使用多线程或多进程来并发执行代码,但是,线程和进程得开销很大,如果需要切换的次数较多,反而降低了效率。所以我们为了能够充分利用线程阻塞得这段时间继续使CPU工作(要知道被阻塞1s中CPU就少计算几百万次),可以使用异步IO的方法:当代码执行到一个IO操作得时候,它只发出IO指令,并不等待结果,而去执行其他得代码,当IO响应的时候在返回处理,这样当有频繁得IO操作得时候,将会大大增加程序得执行效率。
直到异步IO得概念后,gevent的原理就很好理解了。我们还是以程序为例
在work这个方法中,用gevent.sleep(1)来模拟线程阻塞1s的情况,从 程序结果可以看出,当线程遇到阻塞会执行下个协程,等到阻塞结束才会回去处理