python 协程库gevent学习--gevent数据结构及实战(四)
一不留神已经到第四部分了,这一部分继续总结数据结构和常用的gevent类,废话不多说继续。
1.Timeout错误类
晚上在调试调用第三方接口的时候,发现有些接口耗时非常多,觉得应该有个超时接口来限制他们的过长时间的不结束。我开始尝试了requests上面的timeout参数,整个代码流程里面使用到了monkey_patch()但是有个问题,我发现requests.timeout参数在gevent协作的时候表现很奇怪,似乎无法像同步程序这样表现出预想的状况。于是去gevent官方文档里面找寻timeout相关的模块,发现是有的gevent.Timeout继承自BaseException。
我们还是用例子讲解,由于gevent指南上没有介绍这个,我自己写了一个例子先看例子:
import geventfrom gevent import Timeout class NIBAOZHA(BaseException):
pass def haha():
x = gevent.Timeout(1, NIBAOZHA)
x.start()
try:
print 'kaishila'
# gevent.sleep(4) # exception will be raised here, after *seconds* passed since start() call
gevent.sleep(2)
print 'nimei' except NIBAOZHA:
print 'timeout'
finally:
x.cancel() def xixi():
print 'xiba'
gevent.sleep(5)
print 'zhihou' gevent.joinall([gevent.spawn(xixi),
gevent.spawn(haha),
])
Timeout是一个错误类,主要用法是实例化它,然后制定一个超时时间如果有想要抛出的异常第二个参数填写想要抛出的异常。
如果当前greenlet在Timeout调用完start()之后超过了超时时间,就会抛出相应的异常,没有指定异常的话就会抛出gevent.Timeout异常。
这一段代码里面可能有个地方会引起的注意,为什么要用finally? 因为如果在try里面之前有其他地方抛出了被捕获的异常,可能导致后面抛出无法预料到的timeout异常,所以最好关闭掉这个没有被触发的超时异常。
文档里面还介绍了一些方便的写法例如实现了上下文管理协议等 详见:
http://www.gevent.org/gevent.html#timeouts
2. 锁和信号量(locks and semaphores):
信号量是一个允许greenlet从底层互相协作用的一个东西,可以限制并发访问互斥的资源。
信号量有两个方法,acquire和release。在信号量是否已经被 acquire或release,和拥有资源的数量之间不同,被称为此信号量的范围 (the bound of the semaphore)。
如果一个信号量的范围已经降到0,那么会阻塞acquire操作直到有其他家伙释放。
以上的话摘自gevent学习指南,我相信第一次看的朋友绝对一脸蒙比。。什么意思?
下面先来看代码,然后我来翻译一下这个意思:
from gevent import sleep
from gevent.pool import Pool
from gevent.coros import BoundedSemaphore sem = BoundedSemaphore(2) def worker1(n):
sem.acquire()
print('Worker %i acquired semaphore' % n)
sleep(0)
sem.release()
print('Worker %i released semaphore' % n) def worker2(n):
with sem:
print('Worker %i acquired semaphore' % n)
sleep(0)
print('Worker %i released semaphore' % n) pool = Pool()
pool.map(worker1, xrange(0,2))
pool.map(worker2, xrange(3,6))
对比一下和下面代码的运行结果:
from gevent import sleep
from gevent.pool import Pool
from gevent.lock import BoundedSemaphore sem = BoundedSemaphore(2) def worker1(n):
# sem.acquire()
print('Worker %i acquired semaphore' % n)
sleep(0)
# sem.release()
print('Worker %i released semaphore' % n) def worker2(n):
# with sem:
print('Worker %i acquired semaphore' % n)
sleep(0)
print('Worker %i released semaphore' % n) pool = Pool()
pool.map(worker1, xrange(0,2))
pool.map(worker2, xrange(3,6))
其实不用再多说什么你也应该了解了,当我们使用底层同步元语对象BoundSemaphore(2)初始化两个范围之后,就意味着,同时只能有两个greenlet去拿到这两个锁,在这两个锁被aquire之后,其他人必须等待其被relase,否则无法再继续并发更多的greenlet。上面对比就是个好例子,第一组代码的运行先spawn两个greenlet去拿到锁然后释放锁,这里似乎没有什么不一样。但是work2中你会发现,有锁的话你只能看到3,4一起运行然后再运行5。如果没有sem,3,4,5将会同时运行。而且从代码来看,semaphore还支持上下文管理器,看起来还蛮友好的,更多api和介绍参考文档:http://www.gevent.org/gevent.lock.html
3.线程局部变量(Thread Locals):
Gevent也允许你指定局部于greenlet上下文的数据。 在内部,它被实现为以greenlet的getcurrent()为键, 在一个私有命名空间寻址的全局查找。
一言不合先上代码:
import gevent
from gevent.local import local x = local()
def f1():
x.x = 1
print x.x
print x.__dict__ def f2():
x.y = 2
print(x.y) try:
print x.__dict__
except AttributeError:
print("x is not local to f2") g1 = gevent.spawn(f1)
g2 = gevent.spawn(f2) gevent.joinall([g1, g2])
这里先初始化了一个线程本地对象local,给x。然后x会把保存给它的属性当作线程本地变量给存储起来。当其他greenlet去访问它的时候是无法访问到的,它只在自己的greenlet的命名空间中有效。这样可以让我们用来做一些有趣的事情,比如打印属于该greenlet的log日志,将日志存储在greenlet本地local()中从而与其它greenlet互不影响,在协程切换的时候也能打出完整日志。还有这是不是很容易让我们联想到常用python web应用框架flask的requests实现?一个requests就是一个http访问,在整个访问过程中我们可以从requests对象里面拿到很多参数,但是它和其他的requests互不影响,这就是线程本地变量的作用。
另外再提一点,genvent.local还可以被继承实现基于当前greenlet能访问的一组属性的自己的类,来看代码:
import gevent
from gevent.local import local class MyLocal(local):
__slots__ = ('number', 'x') # number = 2
initialized = False def __init__(self, **kw):
if self.initialized:
raise SystemError('__init__ called too many times')
self.initialized = True
self.__dict__.update(kw) def squared(self):
return self.number ** 2 stash = MyLocal() def f1():
stash.x = 1
stash.number = 3
print stash.x
print stash.number def f2():
stash.y = 2
print(stash.y) try:
print stash.x
print stash.number
except AttributeError:
print("x is not local to f2") g1 = gevent.spawn(f1)
g2 = gevent.spawn(f2) gevent.joinall([g1, g2])
这里Mylocal继承了gevent的local,这里重点介绍一下__slots__在这里的用法,我们知道在常规的类里面指定__slots__的意思往往是只允许该类下的属性只允许有__slots__里面这些,超出的就会报出Attribute error的错误。但是继承了local的__slots__在这里却是指,申明了的属性将会穿透所有greenlet变成一个全局可读的,并不再是线程本地的,这里注意下。 其他的都没有什么好说的了。
就这样吧,我将最后的actors模式和gevent子进程还有一些要说的话留在第五讲。
python 协程库gevent学习--gevent数据结构及实战(四)的更多相关文章
- python协程详解,gevent asyncio
python协程详解,gevent asyncio 新建模板小书匠 #协程的概念 #模块操作协程 # gevent 扩展模块 # asyncio 内置模块 # 基础的语法 1.生成器实现切换 [1] ...
- python 协程库gevent学习--gevent数据结构及实战(三)
gevent学习系列第三章,前面两章分析了大量常用几个函数的源码以及实现原理.这一章重点偏向实战了,按照官方给出的gevent学习指南,我将依次分析官方给出的7个数据结构.以及给出几个相应使用他们的例 ...
- python 协程库gevent学习--源码学习(一)
总算还是要来梳理一下这几天深入研究之后学习到的东西了. 这几天一直在看以前跟jd对接的项目写的那个gevent代码.为了查错,基本上深入浅出了一次gevent几个重要部件的实现和其工作的原理. 这里用 ...
- python 协程库gevent学习--gevent源码学习(二)
在进行gevent源码学习一分析之后,我还对两个比较核心的问题抱有疑问: 1. gevent.Greenlet.join()以及他的list版本joinall()的原理和使用. 2. 关于在使用mon ...
- python中的协程:greenlet和gevent
python中的协程:greenlet和gevent 协程是一中多任务实现方式,它不需要多个进程或线程就可以实现多任务. 1.通过yield实现协程: 代码: import time def A(): ...
- Python协程与Go协程的区别二
写在前面 世界是复杂的,每一种思想都是为了解决某些现实问题而简化成的模型,想解决就得先面对,面对就需要选择角度,角度决定了模型的质量, 喜欢此UP主汤质看本质的哲学科普,其中简洁又不失细节的介绍了人类 ...
- Python协程与JavaScript协程的对比
前言 以前没怎么接触前端对JavaScript 的异步操作不了解,现在有了点了解一查,发现 python 和 JavaScript 的协程发展史简直就是一毛一样! 这里大致做下横向对比和总结,便于对这 ...
- Python协程(真才实学,想学的进来)
真正有知识的人的成长过程,就像麦穗的成长过程:麦穗空的时候,麦子长得很快,麦穗骄傲地高高昂起,但是,麦穗成熟饱满时,它们开始谦虚,垂下麦芒. --蒙田<蒙田随笔全集> *** 上篇论述了关 ...
- 5分钟完全掌握Python协程
本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理 1. 协程相关的概念 1.1 进程和线程 进程(Process)是应用程序启动的实例,拥有代码.数据 ...
随机推荐
- <mvc:annotation-driven />注解意义(转)
文章转自http://elf8848.iteye.com/blog/875830 http://www.cnblogs.com/shuo1208/p/5552134.html 暂时只知道对json的支 ...
- TStack与IBM LinuxONE通过兼容性认证
近日,腾讯云TStack与IBM LinuxONE通过兼容性认证,通过腾讯云TStack,可实现便捷管理IBM LinuxONE服务器.这为腾讯和IBM在未来多方面的商业合作奠定了坚实基础,也为腾讯云 ...
- Intel CPU 漏洞分析
Intel CPU漏洞分析报告 预备知识 存储分级 由于计算机存储分级的特性(第一级:寄存器,第二级:高速缓存,第三级:内存,第四级:磁盘),每一级之间的访问速度差距高达数量级.所以处理器会将用到的数 ...
- Android TextView的属性设置为textstyle="bold"时 中文的“¥”不显示
昨天在修改列表的时候出现了一个挺让人纠结的问题.在TextView中“¥”符号无论如何也显示不出来.尝试了使用气的特殊符号,都是能够正确显示的. 最后百度google了一圈也没找出个所以然来.于是觉得 ...
- 零基础入门到精通:Python大数据与机器学习之Pandas-数据操作
在这里还是要推荐下我自己建的Python开发学习群:483546416,群里都是学Python开发的,如果你正在学习Python ,小编欢迎你加入,大家都是软件开发党,不定期分享干货(只有Python ...
- SQL Server CTE 递归查询全解(转载)
在TSQL脚本中,也能实现递归查询,SQL Server提供CTE(Common Table Expression),只需要编写少量的代码,就能实现递归查询,本文详细介绍CTE递归调用的特性和使用示例 ...
- 搭建SpringBoot+dubbo+zookeeper+maven框架(一)
这几天项目还没来,所以就自己试着参考网上的一些资料,搭建了一个SpringBoot+dubbo+zookeeper+maven框架,网上参考的很多资料照着他们一步一步搭建,最后很多都运行不通,很是郁闷 ...
- 【nodejs】让nodejs像后端mvc框架(asp.net mvc)一样处理请求--控制器和处理函数的注册篇(4/8)【controller+action】
文章目录 前情概要 前边的文章把一些基本的前置任务都完成了.接下就是比较重要的处理函数action是如何自动发现和注册的拉,也就是入口函数RouteHandler(也是我们的第一个express中间件 ...
- 2019年以后ArcGIS 调用天地图的资源URL
2019年1月1日起,天地图做出如下变更,导致直接在Arcgis/ArcMap中添加WMTS服务不能用了. 国家天地图解释的很清楚,注册个人用户就可以了. 原有调用方式不变,只要在URL 后添加“&a ...
- M1事后分析汇报以及总结
一.设想和目标 1. 们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述? 我们的软件主要是为了提供周边美食和菜谱查询功能,为“吃货”们提供便利.对典型用户和场景有清晰的描 ...