一不留神已经到第四部分了,这一部分继续总结数据结构和常用的gevent类,废话不多说继续。

1.Timeout错误类

晚上在调试调用第三方接口的时候,发现有些接口耗时非常多,觉得应该有个超时接口来限制他们的过长时间的不结束。我开始尝试了requests上面的timeout参数,整个代码流程里面使用到了monkey_patch()但是有个问题,我发现requests.timeout参数在gevent协作的时候表现很奇怪,似乎无法像同步程序这样表现出预想的状况。于是去gevent官方文档里面找寻timeout相关的模块,发现是有的gevent.Timeout继承自BaseException。

我们还是用例子讲解,由于gevent指南上没有介绍这个,我自己写了一个例子先看例子:

importgeventfrom gevent importTimeoutclassNIBAOZHA(BaseException):pass

defhaha():

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'

exceptNIBAOZHA:print 'timeout'

finally:

x.cancel()defxixi():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 importsleepfrom gevent.pool importPoolfrom gevent.coros importBoundedSemaphore

sem= BoundedSemaphore(2)defworker1(n):

sem.acquire()print('Worker %i acquired semaphore' %n)

sleep(0)

sem.release()print('Worker %i released semaphore' %n)defworker2(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 importsleepfrom gevent.pool importPoolfrom gevent.lock importBoundedSemaphore

sem= BoundedSemaphore(2)defworker1(n):#sem.acquire()

print('Worker %i acquired semaphore' %n)

sleep(0)#sem.release()

print('Worker %i released semaphore' %n)defworker2(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()为键, 在一个私有命名空间寻址的全局查找。

一言不合先上代码:

importgeventfrom gevent.local importlocal

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能访问的一组属性的自己的类,来看代码:

importgeventfrom gevent.local importlocalclassMyLocal(local):__slots__ = ('number', 'x')#number = 2

initialized =Falsedef __init__(self, **kw):ifself.initialized:raise SystemError('__init__ called too many times')

self.initialized=True

self.__dict__.update(kw)defsquared(self):return self.number ** 2stash=MyLocal()deff1():

stash.x= 1stash.number= 3

printstash.xprintstash.numberdeff2():

stash.y= 2

print(stash.y)try:printstash.xprintstash.numberexceptAttributeError: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 协程库_python 协程库gevent学习--gevent数据结构及实战(四)相关推荐

  1. python 协程库_python --- 协程编程(第三方库gevent的使用)

    1. 什么是协程? 协程(coroutine),又称微线程.协程不是线程也不是进程,它的上下文关系切换不是由CPU控制,一个协程由当前任务切换到其他任务由当前任务来控制.一个线程可以包含多个协程,对于 ...

  2. python 协程库_python协程概念

    什么是协程 协程是单线程下的并发,又称微线程,纤程.它是实现多任务的另一种方式,只不过是比线程更小的执行单元.因为它自带CPU的上下文,这样只要在合适的时机,我们可以把一个协程切换到另一个协程.英文名 ...

  3. python从零开始到放弃_Python 协程从零开始到放弃

    0x00 前言 很久以前就听说 Python 的 async/await 很厉害,但是直到现在都没有用过,一直都在用多线程模型来解决各种问题.最近看到隔壁的 Go 又很火,所以决定花时间研究下 Pyt ...

  4. python携程多核_python 协程

    最近对Python中的协程挺感兴趣,这里记录对协程的个人理解. 要理解协程,首先需要知道生成器是什么.生成器其实就是不断产出值的函数,只不过在函数中需要使用yield这一个关键词将值产出.下面来看一个 ...

  5. python加密库_python基于pyDes库实现des加密的方法

    本文实例讲述了python基于pyDes库实现des加密的方法.分享给大家供大家参考,具体如下: 下载及简介地址:https://twhiteman.netfirms.com/des.html 如需要 ...

  6. time库是python中处理时间的标准库_python语言time库和datetime库基本使用详解

    今天是边复习边创作博客的第三天,我今年大二,我们专业开的有这门课程,因为喜欢所以更加认真学习,本以为没人看呢,看了后台浏览量让我更加认真创作,这篇博客花了2个半小时的时间,结合自己所学,所思,所想写作 ...

  7. python库_python使用ctypes库调用DLL动态链接库_python

    最近要使用python调用C++编译生成的DLL动态链接库,因此学习了一下ctypes库的基本使用. ctypes是一个用于Python的外部函数库,它提供C兼容的数据类型,并允许在DLL或共享库中调 ...

  8. python怎么用第三方库_python中第三方库的下载方法

    1.最常用:在命令行中输入  pip install "库名称"  例如 pip install gensim 查看pip的命令集: pip uninstall "库名& ...

  9. python requests下载图片_Python使用urllib库、requests库下载图片的方法比较

    我们知道,使用Python制作一个爬虫程序,requests库是一个不错的选择,requests发送网络请求非常简单,比较使用urllib库,使用requests库可以大大减少代码量,它还可以定制请求 ...

最新文章

  1. avrstudio5 拨码管
  2. jQuery学习入门总结之css()和addClass()的不同
  3. java消息通信_原生 Java 客户端进行消息通信
  4. 10、MySQL锁等待,死锁,死锁检测
  5. 五大经典算法之动态规划
  6. 在mysql中删除表正确的是什么_在MySQL中删除表的操作教程
  7. geometry-api-java 学习笔记(八)分割Intersection
  8. java元注解 @Documented注解使用
  9. sql oltp_内存中的OLTP系列– SQL Server 2014上的数据迁移指南过程
  10. iPhone唯一标识符
  11. c#类的多态和文件流复习
  12. NP、OSPF监测调试
  13. PL/SQL 包头和包体
  14. 接口测试通用测试用例
  15. bootstrop table api
  16. 紧固件基础知识之规格篇和功能篇
  17. Protel DXP 使用教程 - 自定义集成库
  18. 鸡兔同笼。已知鸡兔总头数为h,总脚数为f,求鸡兔各有多少只?
  19. 计算机病毒与蠕虫的特点比较,蠕虫病毒的特点是什么
  20. 程序员为什么要学习算法?

热门文章

  1. 基于javaweb+mysql的个人日记管理系统
  2. Android原生OS风格ROM包,小米5 的LineageOS14.1刷机包 安卓7.1.1原生风格 20180203更新
  3. 合格CTO附加值:CTO教你怎样把一个价值0.5元苹果卖到100万元
  4. ASIHTTPRequest 状态栏网络等待指示器
  5. ios自动订阅服务器,iOS IAP - 自动续期订阅
  6. 斜线表头html怎么做,Excel三栏斜线表头的完美制作方法
  7. excel制作斜线表头
  8. MATLAB 画柱状图:更改横轴显示内容,调整横轴显示角度,纵轴加百分号%,调整纵轴显示范围,柱状图顶添加数字
  9. Nginx添加腾讯安全HTTPS证书
  10. 在Termux中安装Kali教程