文档章节

基础入门_Python—Gevent异步/状态获取/超时设置/猴子补丁

乐搏学院
 乐搏学院
发布于 2017/02/27 11:12
字数 2090
阅读 438
收藏 0
点赞 0
评论 0

简单介绍:

说明: Gevent是一个基于libev的并发库,为各种并发和网络相关的任务提供了整洁的API

 

快速安装:

pip install --upgrade gevent

 

主要模式:

说明: Greenlet以C扩展模块形式接入PY轻量级协程,它们运行于主进程内部,被协作式的调度,且不同于multiprocessing和threading等真正的并行执行,它在同一时刻只能有一个协程在运行

公有方法
gevent.spawn(cls, *args, **kwargs) 创建一个Greenlet对象,其实调用的是Greenlet.spawn(需要from gevent import Greenlet),返回greenlet对象
gevent.joinall(greenlets, timeout=None, raise_error=False, count=None) 等待所有greenlets全部执行完毕, greenlets为序列,timeout为超时计时器对象,返回执行完毕未出错的的greenlet序列
greenlet
g.join() 等待此协程执行完毕后

1. 使用基本封装类初始化Greenlets

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

#!/usr/bin/env python

# -*- coding: utf-8 -*-

"""

#

# Authors: limanman

# OsChina: http://xmdevops.blog.51cto.com/

# Purpose:

#

"""

# 说明: 导入公共模块

import gevent

# 说明: 导入其它模块

def task001():

    print 'I'

    gevent.sleep(0)

    print '#=> switch to task002 run.'

    print 'You'

def task002():

    print 'LOVE'

    gevent.sleep(0)

    print '#=> switch to task001 run.'

if __name__ == '__main__':

    gevent.joinall([

        gevent.spawn(task001),

        gevent.spawn(task002)

    ])

2. 继承Greenlets基类重载_run方法

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

#!/usr/bin/env python

# -*- coding: utf-8 -*-

"""

#

# Authors: limanman

# OsChina: http://xmdevops.blog.51cto.com/

# Purpose:

#

"""

# 说明: 导入公共模块

import gevent

from gevent import Greenlet

# 说明: 导入其它模块

class Gevent(Greenlet):

    def __init__(self, msg, *args, **kwargs):

        super(Gevent, self).__init__(*args, **kwargs)

        self.msg = msg

    # 重载run方法,join后会自动调用此方法执行

    def _run(self):

        print self.msg

        gevent.sleep(0)

if __name__ == '__main__':

    for in ('I''LOVE''YOU'):

        = Gevent(_)

        g.start()

        g.join()

 

 

注意: 多条gevent.spawn(cls, *args, **kwargs).join()语句即使为阻塞调用也不会协程式调用,因为生成的Greenlet对象执行完就消失,所有要实现协程式调用可通过gevent.joinall(greenlets, timeout=None, raise_error=False, count=None)或是赋值到一变量后再对此对象调用.join(),其中一个特殊的方式就是for循环调用将隐式的赋值对象调用,会自动变为协程式运行.

 

同步异步:

说明: 并发的核心在于可拆分成小任务的大任务被分成子任务然后被上下文切换调度,在Gevent中,上下文切换调度是通过yielding来完成的,默认自动切换上下文,当然也可手动gevent.sleep(0)切换上下文

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

#!/usr/bin/env python

# -*- coding: utf-8 -*-

"""

#

# Authors: limanman

# OsChina: http://xmdevops.blog.51cto.com/

# Purpose:

#

"""

# 说明: 导入公共模块

import gevent

# 说明: 导入其它模块

def task001():

    print 'I'

    gevent.sleep(0)

    print '#=> switch to task002 run.'

    print 'You'

def task002():

    print 'LOVE'

    gevent.sleep(0)

    print '#=> switch to task001 run.'

if __name__ == '__main__':

    gevent.joinall([

        gevent.spawn(task001),

        gevent.spawn(task002)

    ])

说明: 如上实例手动调用gevent.sleep(0)来切换上下文,将生成的调度任务通过gevent.joinall加入调度队列,使得只有执行完调度队列的任务后才能继续往下走,一旦调度任务出现阻塞则立即切换到下一个上下文执行

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

#!/usr/bin/env python

# -*- coding: utf-8 -*-

"""

#

# Authors: limanman

# OsChina: http://xmdevops.blog.51cto.com/

# Purpose:

#

"""

# 说明: 导入公共模块

import socket

import gevent

from gevent import select

# 说明: 导入其它模块

def handler(server, port):

    r_list, w_list, e_list = [server], [], []

    while True:

        r, w, e = select.select(r_list, w_list, e_list)

        for sock in r:

            if sock is server:

                c_sock, c_addr = sock.accept()

                r_list.append(c_sock)

                print 'found notice: client #%s connectd to port #%s' % (c_addr, port)

            else:

                data = sock.recv(1024)

                data = data.strip()

                if data in ('quit''exit'):

                    sock.close()

                    r_list.remove(sock)

                    print 'found notice: client #%s disconnectd' % (sock.getpeername(),)

                else:

                    print 'found notice: client #%s send data #%s to port #%s' % (sock.getpeername(), data, port)

if __name__ == '__main__':

    slist = []

    ports = [80018002]

    for in ports:

        server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

        server.bind(('0.0.0.0', p))

        server.listen(10000)

        slist.append(gevent.spawn(handler, server, p))

    gevent.joinall(slist)

说明: Gevent使得函数协作式调度,对于我们隐藏的所有实现细节,保证网络库在可能的时候,隐式交出上下文执行权,上面实例中利用协程+多路复用I/O SELECT实现同时绑定多个端口处理数据的ECHO SERVER,我并没有显式的调用gevent.sleep(0),但是依然执行着上下文切换,这说明当我们在受限于网络或IO的函数中调用gevent时会隐式的切换上下文来实现协作式调度.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

#!/usr/bin/env python

# -*- coding: utf-8 -*-

"""

#

# Authors: limanman

# OsChina: http://xmdevops.blog.51cto.com/

# Purpose:

#

"""

# 说明: 导入公共模块

import time

import pprint

import multiprocessing

from gevent.pool import Pool

# 说明: 导入其它模块

def echo_data(data):

    time.sleep(0.001)

    return data

if __name__ == '__main__':

    # 多进程 - 进程池

    res = []

    = multiprocessing.Pool(10)

    for in xrange(10):

        res.append(list(p.imap_unordered(echo_data, [_ for in xrange(10)])))

    p.close()

    p.join()

    pprint.pprint(res)

    print '################################'

    # 协程式 - 协程池

    res = []

    = Pool(20)

    for in xrange(10):

        res.append(list(p.imap_unordered(echo_data, [_ for in xrange(10)])))

    pprint.pprint(res)

说明: Gevent在相同调用相同输入相同SLEEP时产生的结果总是相同的,相对于多进程/多线程的即使在相同调用相同输入相同SLEEP下结果不总相同

注意: Gevent在处理不确定阻塞时间调用时,你的程序可能会出现不确定性,这是由于并发通病-竞争条件导致,最好的解决办法是尽量避免所有的全局状态.避免竞争访问或是修改.

 

状态获取:

说明: Greenlet可能由于不同的原因运行失败,但其并不会抛出异常,而是用状态变量/方法跟踪线程内部的状态

状态相关
g.started 协程是否已经启动
g.ready() 协程是否已经停止
g.successful() 同上,但是没有抛异常
g.value 协程返回的值
g.exception 协程内抛出的未捕捉的异常
g.get(block=True, timeout=None) 获取greenlet的返回值或重新抛出运行中异常,timeout设置计时器对象

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

#!/usr/bin/env python

# -*- coding: utf-8 -*-

"""

#

# Authors: limanman

# OsChina: http://xmdevops.blog.51cto.com/

# Purpose:

#

"""

# 说明: 导入公共模块

import gevent

# 说明: 导入其它模块

# 谈情

def love():

    print 'ok'

# 做爱

def makelove():

    raise Exception('fuck')

if __name__ == '__main__':

    greenlets = [gevent.spawn(love), gevent.spawn(makelove)]

    gevent.joinall(greenlets)

    for in greenlets:

        print 'started? %s' % g.started

        print 'ready? %s' % g.ready()

        print 'successful? %s' % g.successful()

        print 'exception? %s' % g.exception

 

 

超时设置:

说明: 超时是一种对代码块儿或Greenlet的运行时间约束

公有方法
gevent.Timeout(seconds, exception) 创建一个计时器对象
Timeout
t.start() 启动一个计时器对象
t.cancel() 取消一个计时器对象
t.start_new(timeout=None, exception=None, ref=True) 创建一个新的计时器对象,timeout为超时时间,默认单位为秒

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

#!/usr/bin/env python

# -*- coding: utf-8 -*-

"""

#

# Authors: limanman

# OsChina: http://xmdevops.blog.51cto.com/

# Purpose:

#

"""

# 说明: 导入公共模块

import gevent

# 说明: 导入其它模块

def run_forever(interval):

    while True:

        gevent.sleep(interval)

if __name__ == '__main__':

    timer = gevent.Timeout(1).start()

    = gevent.spawn(run_forever, 1000000)

    # 执行超时

    try:

        g.join(timeout=timer)

    except gevent.Timeout, e:

        print 'found error: thread 1 timeout.'

    # 获取超时

    timer = gevent.Timeout.start_new(1)

    = gevent.spawn(run_forever, 1000000)

    try:

        g.get(timeout=timer)

    except gevent.Timeout, e:

        print 'found error: thread 2 timeout.'

    # 执行超时

    try:

        gevent.with_timeout(1, run_forever, 1000000)

    except gevent.Timeout, e:

        print 'found error: thread 3 timeout.'

 

猴子补丁:

说明: PY的默认运行环境允许我们运行中修改大部分对象,包括模块/类/函数等,而猴子补丁可以修改PY标准库里面大部分的阻塞式系统调用,实在不知哪些库可打补丁可gevent.monkey.patch_all()即可.

patch_all/patch_builtins/patch_dns/patch_item/patch_module/patch_os/patch_select/patch_signal/patch_socket/patch_ssl/patch_subprocess/patch_sys/patch_thread/patch_time

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

#!/usr/bin/env python

# -*- coding: utf-8 -*-

"""

#

# Authors: limanman

# OsChina: http://xmdevops.blog.51cto.com/

# Purpose:

#

"""

# 说明: 导入公共模块

import select

# 说明: 导入其它模块

if __name__ == '__main__':

    print '#select before path %s' % (select.select,)

    from gevent import monkey

    monkey.patch_all()

    print '#select after path %s' % (select.select,)

 

 

登录乐搏学院官网http://www.learnbo.com/

或关注我们的官方微博微信,还有更多惊喜哦~

 

本文出自 “满满李 - 运维开发之路” 博客,请务必保留此出处http://xmdevops.blog.51cto.com/11144840/1862085

© 著作权归作者所有

共有 人打赏支持
乐搏学院
粉丝 6
博文 526
码字总数 707467
作品 0
丰台
程序员
python学习笔记 | Python中并行IO操作的内存效率

Python允许多种不同的并行处理方法。并行性的主要问题是了解其局限性。我们要么平行IO操作或像图像处理这样的CPU限制任务。 在Python 3.5之前,有两种方法可以并行处理IO绑定操作。本地方法是...

跨界的聚能 ⋅ 05/24 ⋅ 0

荐书丨确认过眼神,这份Python书单一定是你的菜

点击上方“程序人生”,选择“置顶公众号” 第一时间关注程序猿(媛)身边的故事 Python 是军刀型的开源工具,被广泛应用于Web 开发、爬虫、数据清洗、自然语言处理、机器学习和人工智能等方...

csdnsevenn ⋅ 05/05 ⋅ 0

一个月入门Python爬虫,快速获取大规模数据

数据是创造和决策的原材料,高质量的数据都价值不菲。而利用爬虫,我们可以获取大量的价值数据,经分析可以发挥巨大的价值,比如: 豆瓣、知乎:爬取优质答案,筛选出各话题下热门内容,探索...

Python开发者 ⋅ 04/25 ⋅ 0

156个Python网络爬虫资源,妈妈再也不用担心你找不到资源了

本列表包含Python网页抓取和数据处理相关的库。 前几天有私信小编要Python的学习资料,小编整理了一些有深度的Python教程和参考资料,从入门到高级的都有,文件已经打包好了,正在学习Pytho...

雁横 ⋅ 05/02 ⋅ 0

Python gevent学习笔记 2

在上一篇里了解了gevent应用的IO模型概念之后,接下来开始真正了解gevent的使用。 Greenlet 在gevent里面最多应用到的就是greenlet,一个轻量级的协程实现。在任何时间点,只有一个greenlet处...

贱圣 ⋅ 2013/06/30 ⋅ 0

什么样的人学Python比别人快?Python的学习大纲有哪些?

什么样的人学Python比别人快? 为什么会是这些人?前两类大家应该都没什么意见,为什么最后两类会学得快?这两类说白了就一个关键词:转行!既然决定转行,有太多需要学习的东西,太多不适应...

帅帅程序员 ⋅ 04/28 ⋅ 0

python掀起了全民学习的热潮?

1、 要说这两年最火的关键词,一定是大数据和人工智能,连国务院都在去年7月发布了我国首个人工智能国家规划——《新一代人工智能发展规划》,从国家层面对人工智能进行顶层设计。 人工智能时...

qq_41597912 ⋅ 04/13 ⋅ 0

异步社区本周(4.23-4.29)半价电子书

点击关注 异步图书,置顶公众号 每天与你分享 IT好书 技术干货 职场知识 《R语言编程指南》 任坤 著 点击封面购买纸书 R 语言是从事数据科学和统计学需要的工具之一。强大且复杂的 R 对于初学...

异步社区 ⋅ 04/24 ⋅ 0

5个python爬虫教材,让小白也有爬虫可写,含视频教程!

认识爬虫   网络爬虫,如果互联网是一张蜘蛛网,网络爬虫既是一个在此网上爬行的蜘蛛,爬了多少路程即获取到多少数据。 python写爬虫的优势   其实以上功能很多语言和工具都能做,但是用...

柯西带你学编程 ⋅ 06/12 ⋅ 0

Python学习记录-多进程和多线程

Python学习记录-多进程和多线程 [TOC] 1. 进程和线程 进程 狭义定义:进程是正在运行的程序的实例(an instance of a computer program that is being executed)。 广义定义:进程是一个具有...

ygqygq2 ⋅ 04/27 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Java集合类总结笔记

一、集合类的层次关系 主要容器集合类的特点: ArrayList 一种可以动态增长和缩减的索引序列 LinkedList 一种可以在任何位置进行高效地插入和删除的有序序列 ArrayDeque 一种用循环数组实现的...

edwardGe ⋅ 7分钟前 ⋅ 0

spring RMI远程调用

RMI https://www.cnblogs.com/wdh1995/p/6792407.html

BobwithB ⋅ 12分钟前 ⋅ 0

Jenkins实践2 之基本配置

1 插件管理 系统管理->插件管理 在可选插件中可以自主安装插件 2 管理用户 系统管理->管理用户->新建用户 3 安全配置 系统管理->全局安全配置 授权策略 选择安全矩阵 然后添加现有的用户,赋...

晨猫 ⋅ 12分钟前 ⋅ 0

c++智能指针

1、是一种泛型类,针对指针类型的泛型类,会保存指针 2、重载了符号 *和-> 对智能指针使用这两个符号,相当于对保存的泛型使用这两个符号 3、当智能指针引用计数为0时,会去释放指针指向的资...

国仔饼 ⋅ 13分钟前 ⋅ 0

Spring Boot错误处理机制

1)、SpringBoot默认的错误处理机制 默认效果: 1)、浏览器,返回一个默认的错误页面 浏览器发送请求的请求头: 2)、如果是其他客户端,默认响应一个json数据 原理: 可以参照ErrorMvcAut...

小致dad ⋅ 15分钟前 ⋅ 0

ftp连接不上的终极办法 SFTP

假如FTP由于各种原因就是连不上,那么用SFTP协议吧,使用登录服务器的账号密码。

sskill ⋅ 19分钟前 ⋅ 0

Unity 围绕旋转角度限制(Transform.RotateAround)

在 Unity 中可以利用 Transform.RotateAround 围绕指定物体进行旋转,但某些情况下可能需要对旋转角度进行控制。我是先计算出预设角度大小,然后判断是否在限定角度范围内是则进行旋转。 相关...

大轩 ⋅ 20分钟前 ⋅ 0

阿里沙箱环境支付宝测试demo

阿里支付宝支付和微信支付,包括:阿里沙箱环境支付宝测试demo,支付宝支付整合到spring+springmvc+mybatis环境和微信整合到如上环境,功能非常齐全,只需要修改对应的配置文件即可,帮助文档...

码代码的小司机 ⋅ 23分钟前 ⋅ 0

JDK1.6和JDK1.7中,Collections.sort的区别,

背景 最近,项目正在集成测试阶段,项目在服务器上运行了一段时间,点击表格的列进行排序的时候,有的列排序正常,有的列在排序的时候,在后台会抛出如下异常,查询到不到数据,而且在另外一...

tsmyk0715 ⋅ 40分钟前 ⋅ 0

C++ 中命名空间的 5 个常见用法

相信小伙伴们对C++已经非常熟悉,但是对命名空间经常使用到的地方还不是很明白,这篇文章就针对命名空间这一块做了一个叙述。 命名空间在1995年被引入到 c++ 标准中,通常是这样定义的: 命名...

柳猫 ⋅ 44分钟前 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部