协程:Greenlet模块Gevent模块

Posted python-by-xiaoma

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了协程:Greenlet模块Gevent模块相关的知识,希望对你有一定的参考价值。

三、Greenlet模块                                                            

技术分享图片
Greenlet是python的一个C扩展,来源于Stackless python,旨在提供可自行调度的‘微线程’, 即协程。generator实现的协程在yield value时只能将value返回给调用者(caller)。 而在greenlet中,target.switch(value)可以切换到指定的协程(target), 然后yield value。greenlet用switch来表示协程的切换,从一个协程切换到另一个协程需要显式指定。


安装 :pip3 install greenlet
简介:
技术分享图片
from greenlet import greenlet

def eat(name):
    print(%s eat 1 %name)
    g2.switch(egon)
    print(%s eat 2 %name)
    g2.switch()
def play(name):
    print(%s play 1 %name)
    g1.switch()
    print(%s play 2 %name)

g1=greenlet(eat)
g2=greenlet(play)

g1.switch(egon)#可以在第一次switch时传入参数,以后都不需要
greenlet实现状态切换

有几个缺点
1.手动切换
2.不能规避I/O操作(睡眠)

 

gevent模块 

技术分享图片
安装:pip3 install gevent

Gevent 是一个第三方库,可以轻松通过gevent实现并发同步或异步编程,在gevent中用到的主要模式是Greenlet, 它是以C扩展模块形式接入Python的轻量级协程。 Greenlet全部运行在主程序操作系统进程的内部,但它们被协作式地调度。
介绍、安装
技术分享图片
g1=gevent.spawn(func,1,,2,3,x=4,y=5)创建一个协程对象g1,spawn括号内第一个参数是函数名,如eat,后面可以有多个参数,可以是位置实参或关键字实参,都是传给函数eat的

g2=gevent.spawn(func2)

g1.join() #等待g1结束

g2.join() #等待g2结束

#或者上述两步合作一步:gevent.joinall([g1,g2])

g1.value#拿到func1的返回值



#例:遇到io主动切换

from gevent import monkey;monkey.patch_all()

import gevent
import time
def eat():
    print(eat food 1)
    time.sleep(2)
    print(eat food 2)

def play():
    print(play 1)
    time.sleep(1)
    print(play 2)

g1=gevent.spawn(eat)
g2=gevent.spawn(play)
gevent.joinall([g1,g2])
print()
用法介绍
技术分享图片
真正能实现协程的模块gevent

import gevent
def eat():
    print(eating1)
    print(eating2)
g1 = gevent.spawn(eat)  #创建一个协程对象g1
#执行输出为空,表示它还没执行。


import gevent
def eat():
    print(eating1)
    print(eating2)
g1 = gevent.spawn(eat)  #创建一个协程对象g1
g1.join()  #等待g1结束

#执行输出:

#eating1
#eating2
例子

geven 不能识别time.sleep()  需要用gevent.sleep()  或者导入一个模块monkey;monkey patch (猴子补丁)

技术分享图片
#如果想让协程执行time.sleep()呢?由于默认,协程无法识别time.sleep()方法,需要导入一个模块monkey

#monkey patch (猴子补丁)
#用来在运行时动态修改已有的代码,而不需要修改原始代码。

from gevent import monkey;monkey.patch_all()
# 它会把下面导入的所有的模块中的IO操作都打成一个包,gevent就能够认识这些IO了
import time
import gevent
def eat():
    print(eating1)
    time.sleep(1)  #延时调用
    print(eating2)
 
def play():
    print(playing1)
    time.sleep(1)  #延时调用
    print(playing2)
 
g1 = gevent.spawn(eat)  #创建一个协程对象g1
g2 = gevent.spawn(play)
g1.join()  #等待g1结束
g2.join()

#执行输出:

eating1
playing1
eating2
playing2
使用

结论:

使用gevent模块来执行多个函数,表示在这些函数遇到IO操作的时候可以在同一个线程中进行切换
利用其他任务的IO阻塞时间来切换到其他的任务继续执行

前提是:

spawn来发布协程任务
join负责开启并等待任务执行结束
gevent本身不认识其他模块中的IO操作,但是如果我们在导入其他模块之前执行from gevent import monkey;monkey.patch_all()  这行代码,必须在文件最开头
gevent就能够认识在这句话之后导入的模块中的所有IO操作了

Gevent之同步与异步

技术分享图片
from gevent import spawn,joinall,monkey;monkey.patch_all()
 
import time
def task(pid):
    """
    Some non-deterministic task
    """
    time.sleep(0.5)
    print(Task %s done % pid)
 
 
def synchronous():  # 同步
    for i in range(10):
        task(i)
 
def asynchronous(): # 异步
    g_l=[spawn(task,i) for i in range(10)]
    joinall(g_l)
    print(DONE)
     
if __name__ == __main__:
    print(Synchronous:)
    synchronous()
    print(Asynchronous:)
    asynchronous()
#  上面程序的重要部分是将task函数封装到Greenlet内部线程的gevent.spawn。
#  初始化的greenlet列表存放在数组threads中,此数组被传给gevent.joinall 函数,
#  后者阻塞当前流程,并执行所有给定的greenlet任务。执行流程只会在 所有greenlet执行完后才会继续向下走。
实例

当一个任务执行时,依赖另外一个任务的结果时,这种情况不适合异步,只能用同步

Gevent之应用举例一

Gevent之应用举例二







以上是关于协程:Greenlet模块Gevent模块的主要内容,如果未能解决你的问题,请参考以下文章

并发编程 - 协程 - 1.协程概念/2.greenlet模块/3.gevent模块/4.gevent实现并发的套接字通信

网络编程之协程——gevent模块

python 并发编程 协程 gevent模块

Python协程之Gevent

Python并发编程:协程-gevent模块

# 进程/线程/协程 # IO:同步/异步/阻塞/非阻塞 # greenlet gevent # 事件驱动与异步IO # SelectPollEpoll异步IO 以及selectors模块 # (示