python 协程 及其与python多线程的区别和联系

一、协程(coroutine)又称微线程,纤程,是种用户级别的轻量级线程。

协程拥有自己的寄存器上下文和栈。协程调度切换时候,将寄存器上下文和栈保存到其他地方,等待切换回来的时候恢复,并从之前保存的寄存器上下文 和 栈继续工作。

并发编程中,协程与 线程类似,每个协程表示一个执行单元,有自己的本地数据,与其他协程共享全局数据及资源池。

协程需要操作员单独写调度逻辑,对CPU来说,协程也就是单线程,因此CPU 不需要考虑怎么调度、切换上下文,省去了CPU开销,所以,协程又在一定程度上好于多线程。

二、python中实现协程:

python使用yield 提供对协程的基本支持,但是,第三方的 gevent库能更好地提供该服务,gevent有比较完善的协程支持。

geve 是基于协程的python网络函数库,使用greenlet 在libev事件循环顶部提供一个有高级别并发性的API。

特点:

(1)基于libev 的快速事件循环,Linux上的epoll机制。

(2)基于greenlet的轻量级执行单元。

(3)API 复用了python标准库的内容。

(4)支持SSL的协作式sockets。

(5)可以通过线程池或者c-ares 实现DNS查询。

(6)通过 monkey patching功能使得第三方模块编程协作式。

gevent支持协程,其实也可以说是greenlet实现的工作切换。

greenlet工作流程如下:如果访问网路的I/O操作出现阻塞时,greenlet就显式切换到另外一个没有被阻塞的代码段执行,直到原先的阻塞状态消失后,再自动切换会原来的代码段继续处理。 可以说,greenlet是在更合理地安排串行工作方式。

同时,由于IO 操作比较耗时,经常是程序处于等待状态,gevent自动切换协程后,能够保证总有greenlet在运行,而不需要等待IO完成,这是协程比一般多线程效率高的原因。

IO操作是自动完成的,所以gevent 需要修改python的一些自带标准库,将一些常见的阻塞,如:socket、select等地方实现协程跳转,这一过程可以通过monkey patch完成。

如下代码可以显示 gevent的使用流程:(python版本: 3.6 操作系统环境: windows10)

gevent的spawn方法可以看做是用来形成协程,joinall 方法相当于添加协程任务并启动运行。由结果可以看到,3个网络请求并发执行,而且结束顺序却不一致,但是却只有一个线程。

gevent还提供池。如果拥有动态数量的 greenlet需要进行并发管理,可以使用池 来处理大量的网络请求 及 IO操作。

如下是 gevent的pool对象,修改如上的多网络请求示例:

由结果来看,Pool 对象对协程的并发数量进行了管理,先访问前两个,当其中一个任务完成了,再继续执行第三个请求。

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180508A1UEJ300?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券