其他分享
首页 > 其他分享> > 1.协程

1.协程

作者:互联网

协程 协程不是计算机提供,而是人为创造出来的 协程也可以被称为微线程,是一种用户态内的上下文切换技术,其实就是通过一个线程实现代码块相互切换执行 协程本质上是一个线程上多个代码来回切换执行     协程实现的几种方法:
greenlet:早期的一个实现协程的第三方模块
gevent: 基于greenlet实现的协程,python第三方库
yield关键字
asyncio装饰器 (版本>=py3.4)
async、await关键字 (版本>=3.5,推荐使用)
  greenlet实现协程 创建一个greenlet时,初始化一个空的栈, switch到这个栈的时候, 会运行在greenlet构造时传入的函数
#安装 
pip3 install greenlet
'''比较重要的几个属性'''

switch() #协程切换
getcurrent() #返回当前的greenlet实例
GreenletExit #是一个特殊的异常,当触发了这个异常的时候,即使不处理,也不会抛到其parent
run #当greenlet启动的时候会调用到这个callable,如果我们需要继承greenlet.greenlet时,需要重写该方法
parent #可读写属性
dead #如果greenlet执行结束,那么该属性为true
throw #切换到指定greenlet后立即抛出出异常
 
# 导入
from greenlet import greenlet


def func1():
    print(1)  # 第二步: 输出1
    gr2.switch()  # 第三步: 切换到func2函数
    print(2)  # 第六步:输出2
    gr2.switch()  # 第七步: 切换到func2函数


def func2():
    print(3)  # 第四步:输出4
    gr1.switch()  # 第五步:切换到func1函数
    print(4)  # 第八步:输出4


gr1 = greenlet(func1)
gr2 = greenlet(func2)
gr1.switch()  # 第一步 执行func1函数
    gevent实现协程
#安装 
pip3 install gevent
g1 = gevent.spawn(func,param1,param2) #创建一个g1协程对象,第一个参数是函数名,后面是函数带的参数
g1.join() #等待协程执行
g1.value #拿到方法的返回值
gevent.sleep(s) #IO阻塞指定时间时,切换到其他协程
gevent.joinall([g1,g2]]) # 批量join,可以传入多个方法,不用一个一个join
gevent.queue.Queue # 协程安全队列
gevent.spawn 启动的所有协程,都是运行在同一个线程之中,所以协程不能跨线程同步数据。

gevent 启动的并发协程,具体到任务方法,不能有长时间阻塞的IO操作。因为gevent的协程的特点是,当前协程阻塞了才会切换到别的协程。如果当前协程长时间阻塞,则不能切换到别的协程。导致程序出问题。
如果有长时间阻塞的 IO 操作,还是用传统的线程模型比较好。
gevent 适合处理大量无阻塞的任务,如果有实在不能把阻塞的部分变为非阻塞再交给 gevent 处理,就把阻塞的部分改为异步
默认情况下time.sleep()不能被gevent识别为耗时操作
    1.把time.sleep()替换为gevent.sleep()
    2.添加补丁使gevent可以识别time.sleep()

monkey补丁的作用
    1.在运行时替换方法、属性等
    2.在不修改第三方代码的情况下增加原来不支持的功能
    3.在运行时为内存中的对象增加patch,而不是在磁盘的源代码中增加

gevent
gevent.spawn(func,value1,value2,......)
        功能:创建gevent对象
        参数:
            target:协程执行的函数名

gevent.getcurrent()
        功能:获取当前协程对象

gevent.joinall([args])
        功能:批量为协程执行join()
        参数:需要join()的gevent组成的list

from gevent import monkey
monkey.patch_all()
        功能:破解所有,使gevent可以识别time.sleep()

obj.sleep(time)
        功能:休眠,是gevent可以识别的time.sleep()

obj.join()
        功能:造成阻塞,使主线程等待协程执行完成再结束
#示例1
from gevent import monkey
monkey.patch_all()
# 导入 gevent
import gevent

def work1():
    print('work1')
    gevent.sleep(1)
    print('end1')


def work2():
    print('work2')
    gevent.sleep(1)
    print('end2')


if __name__ == '__main__':

    g1 = gevent.spawn(work1)
    g2 = gevent.spawn(work2)
    # 造成阻塞,阻塞时自动切换其他
    g1.join()
    g2.join()
#示例2-协程池

# gevent的猴子补丁
from gevent import monkey
# 导入协程池
from gevent.pool import Pool
import gevent

monkey.patch_all()




def num(n):
    print(n * n)
    return n * n


if __name__ == '__main__':
    # 实例化一个协程池,参数为最大协程数
    pool = Pool(10) 
    # 生成协程列表,
    p = [pool.spawn(num, i) for i in range(10)]
    gevent.joinall(p)
  yield关键字实现协程
def func1():
    yield 1  # 第一步:返回1
    yield from func2()  # 第二步: 切换到func2
    yield 2  # 第五步:返回2


def func2():
    yield 3  # 第三步:返回3
    yield 4  # 第四步:返回4


f1 = func1()  # 返回一个生成器

for item in f1:
    print(item)
  asyncio实现协程

import asyncio


@asyncio.coroutine
def func1():
    print(1)
    yield from asyncio.sleep(2)  #遇到IO耗时操作,自动切换到tasks中的其他任务
    print(2)

@asyncio.coroutine
def func2():
    print(3)
    yield  from  asyncio.sleep(2)  #遇到IO耗时操作,自动切换到tasks中的其他任务
    print(4)


tasks = [
    asyncio.ensure_future(func1()),
    asyncio.ensure_future(func2())

]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
# 遇到IO阻塞自动切换
  async & await关键字实现协程-推荐使用
import asyncio


async def func1():
    print(1)
    await  asyncio.sleep(2)  # 遇到IO耗时操作,自动切换到tasks中的其他任务
    print(2)


async def func2():
    print(3)
    await  asyncio.sleep(2)  # 遇到IO耗时操作,自动切换到tasks中的其他任务
    print(4)


tasks = [
    asyncio.ensure_future(func1()),
    asyncio.ensure_future(func2())

]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
# 遇到IO阻塞自动切换
 

标签:协程,gevent,greenlet,print,sleep,asyncio
来源: https://www.cnblogs.com/Mickey-7/p/16316007.html