协程的含义就不再提,在py2和py3的早期版本中,python协程的主流实现方法是使用gevent模块。由于协程对于操作系统是无感知的,所以其切换需要程序员自己去完成。

系列文章

基于生成器的简单协程

import time
def A():
for i in range(100):
print("----A---")
yield i
time.sleep(0.5) def B(c):
while True:
print("----B---")
try:
next(c)
except StopIteration:
break
else:
time.sleep(0.5) if __name__ == '__main__':
a = A()
B(a)

上面的例子并没有带来代码效率的提高,因为time.sleep()是同步阻塞操作;上例主要是为了说明协程的上下文切换原理。

greenlet的协程

greenlet模块也是程序显性主动控制协程切换,但是对原生做了一定的封装使得切换变得简单一些。

from greenlet import greenlet
import time def test1(gr,g):
for i in range(100):
print("---A--")
gr.switch(g, gr) # 切换到另一个协程执行
time.sleep(0.5) def test2(gr, g):
for i in range(100):
print("---B--")
gr.switch(g, gr)
# gr.throw(AttributeError)
time.sleep(0.5) if __name__ == '__main__':
# 创建一个协程1
gr1 = greenlet(test1)
# 创建一个协程2
gr2 = greenlet(test2)
# 启动协程
gr1.switch(gr2, gr1)

greenlet类主要有两个方法:

  • switch:用来切换协程;

  • throw():用来抛出异常同时终止程序;

gevent模块协程

  • gevent是在greenlet的基础上进行封装使得gevent变得更加的易用。

  • gevent采用了隐式启动事件循环,即在需要阻塞的时候开启一个专门的协程来启动事件循环;

  • 如果一个任务没有io操作,那么他会一直执行直到完成;其他协程没有执行的机会;

  • 自动识别io事件,放弃CPU控制时间;

# 一个补丁patch_all,注意要放在所有的import前面,其会将线程、进程替换成gevent框架,使得我们可以用同步编程的方式编写异步代码
from gevent import monkey;monkey.patch_all()
import gevent
import requests def target0(n):
print('--start---{}'.format(n))
res = requests.get('http://www.baidu.com')
print(res)
return n if __name__ == '__main__':
jobs = [gevent.spawn(target0, 1),gevent.spawn(target0, 2),gevent.spawn(target0, 3)]
gevent.joinall(jobs)
print([job.value for job in jobs])

gevent模块分析

  • gevent顶层方法
gevent.spawn():创建一个普通的Greenlet对象并切换;
gevent.spawn_later(seconds=3) # 延时创建一个普通的Greenlet对象并切换
gevent.spawn_raw() # 创建的协程对象属于一个组
gevent.getcurrent() # 返回当前正在执行的greenlet
gevent.joinall(jobs):将协程任务添加到事件循环,接收一个任务列表
gevent.wait() # 可以替代join函数等待循环结束,也可以传入协程对象列表
gevent.kill() # 杀死一个协程
gevent.killall() # 杀死一个协程列表里的所有协程
monkey.patch_all():非常重要,会自动将python的一些标准模块替换成gevent框架
  • 设置强制切换的时间
# 手动设置CPU密集型最大执行时间,如果是单线程的协程不需要关注这个
sys.setcheckinterval(n):每n条执行尝试进行线程切换,n必须是int
sys.getswitchinterval() # 默认5ms切换
  • Greenlet对象
# Greenlet对象
from gevent import Greenlet # Greenlet对象创建
job = Greenlet(target0, 3)
Greenlet.spawn() # 创建一个协程并启动
Greenlet.spawn_later(seconds=3) # 延时启动 # 协程启动
job.start() # 将协程加入循环并启动协程
job.start_later(3) # 延时启动 # 等待任务完成
job.join() # 等待任务完成
job.get() # 获取协程返回的值 # 任务中断和判断任务状态
job.dead() # 判断协程是否死亡
job.kill() # 杀死正在运行的协程并唤醒其他的协程,这个协程将不会再执行,可以
job.ready() # 任务完成返回一个真值
job.successful() # 任务成功完成返回真值,否则抛出错误 # 获取属性
job.loop # 时间循环对象
job.value # 获取返回的值 # 捕捉异常
job.exception # 如果运行有错误,获取它
job.exc_info # 错误的详细信息 # 设置回调函数
job.rawlink(back) # 普通回调,将job对象作为回调函数的参数
job.unlink() # 删除回调函数
# 执行成功的回调函数
job.link_value(back)
# 执行失败的回调函数
job.link_exception(back)

限制并发

  • 通过设置协程池Pool来限制运行的协程的最大数目。该Pool和multiprocessing进程模块的Pool的API十分相似。

  • Group类管理一组不限制数目的协程对象,但是Pool是它的子类,使用一般用Pool替代。

def tag():
print('--start---')
x = requests.get('http://www.baidu.com')
print(x)
print('------end--------')
return 0 if __name__ == '__main__': from gevent.pool import Pool
p = Pool(5)
for i in range(10):
p.apply_async(tag)
p.join()
  • gevent.Pool的特殊方法
pool.wait_available():等待直到有一个协程有结果
pool.dd(greenlet):向进程池添加一个方法并跟踪,非阻塞
pool.discard(greenlet):停止跟踪某个协程
pool.start(greenlet):加入并启动协程
pool.join():阻塞等待结束
pool.kill():杀死所有跟踪的协程
pool.killone(greenlet):杀死一个协程

python并发编程之gevent协程(四)的更多相关文章

  1. python并发编程之asyncio协程(三)

    协程实现了在单线程下的并发,每个协程共享线程的几乎所有的资源,除了协程自己私有的上下文栈:协程的切换属于程序级别的切换,对于操作系统来说是无感知的,因此切换速度更快.开销更小.效率更高,在有多IO操作 ...

  2. python并发编程之IO模型 (四十九)

    IO模型介绍 http://www.cnblogs.com/linhaifeng/articles/7454717.html

  3. python并发编程之Queue线程、进程、协程通信(五)

    单线程.多线程之间.进程之间.协程之间很多时候需要协同完成工作,这个时候它们需要进行通讯.或者说为了解耦,普遍采用Queue,生产消费模式. 系列文章 python并发编程之threading线程(一 ...

  4. python并发编程之multiprocessing进程(二)

    python的multiprocessing模块是用来创建多进程的,下面对multiprocessing总结一下使用记录. 系列文章 python并发编程之threading线程(一) python并 ...

  5. python并发编程之threading线程(一)

    进程是系统进行资源分配最小单元,线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.进程在执行过程中拥有独立的内存单元,而多个线程共享内存等资源. 系列文章 py ...

  6. python并发编程之线程/协程

    python并发编程之线程/协程 part 4: 异步阻塞例子与生产者消费者模型 同步阻塞 调用函数必须等待结果\cpu没工作input sleep recv accept connect get 同 ...

  7. Python核心技术与实战——十七|Python并发编程之Futures

    不论是哪一种语言,并发编程都是一项非常重要的技巧.比如我们上一章用的爬虫,就被广泛用在工业的各个领域.我们每天在各个网站.App上获取的新闻信息,很大一部分都是通过并发编程版本的爬虫获得的. 正确并合 ...

  8. Python并发编程——多线程与协程

    Pythpn并发编程--多线程与协程 目录 Pythpn并发编程--多线程与协程 1. 进程与线程 1.1 概念上 1.2 多进程与多线程--同时执行多个任务 2. 并发和并行 3. Python多线 ...

  9. 15.python并发编程(线程--进程--协程)

    一.进程:1.定义:进程最小的资源单位,本质就是一个程序在一个数据集上的一次动态执行(运行)的过程2.组成:进程一般由程序,数据集,进程控制三部分组成:(1)程序:用来描述进程要完成哪些功能以及如何完 ...

随机推荐

  1. nest

    d3.nest d3.nest表示一种嵌套结构.之所以成为嵌套是因为可以指定多个key访问器,这些访问器是一层一层嵌套的. 作用 将数组中的元素对象,按照key方法指定的属性,分组为层次结构.与SQL ...

  2. 两个float 怎么比较大小

    转自:http://blog.csdn.net/mydriverc2/article/details/49888947 float 类型不能比较相等或不等,但可以比较>,<,>=,& ...

  3. HttpHelper类及调用

    首先列出HttpHelper类 /// <summary> /// Http操作类 /// </summary> public class HttpHelper { priva ...

  4. ans menu list

    ans menu list 1. 系统配置 a) 基本设置 i. NTP ii. 配置模式 iii. 主机信息 b) 高可用性 i. 节点 ii. 路由监视器 iii. 故障转移接口群 c) 设备标识 ...

  5. OpenCV图像变换(仿射变换与透视变换)

    仿射变换(affine transform)与透视变换(perspective transform)在图像还原.图像局部变化处理方面有重要意义.通常,在2D平面中,仿射变换的应用较多,而在3D平面中, ...

  6. PID控制算法的C语言实现三 位置型PID的C语言实现

    上一节中已经抽象出了位置性PID和增量型PID的数学表达式,这一节,重点讲解C语言代码的实现过程,算法的C语言实现过程具有一般性,通过PID算法的C语言实现,可以以此类推,设计其它算法的C语言实现. ...

  7. angular2 获取到的数据无法实时更新的问题

    在修改完组件数据之后调用下面两句: this.changeDetectorRef.markForCheck(); this.changeDetectorRef.detectChanges(); 注入到 ...

  8. Socket初识2

    一.Socket一些概念 sk = socket.socket(socket.AF_INET,socket.SOCK_STREAM,0) 1.1 参数1:Socket Families(地址簇) / ...

  9. vue props验证

    <!DOCTYPE html> <html> <head> <title></title> <meta charset="u ...

  10. MySQL建表时列名同保留字重复问题解决办法

    建表时遇到遇到属性名同MySQL的保留字相同导致不能建表的问题,如下SQL语句: CREATE TABLE TBL_ACCOUNT_FROZEN_RECORD ( ID BIGINT NOT NULL ...