协程

协程(coroutine),又称为微线程,纤程。(协程是一种用户态的轻量级线程)

作用:在执行A 函数的时候,可以随时中断,去执行B 函数,然后中断继续执行A 函数(可以自动切换),注意这一过程并不是函数调用(没有调用语句),过程很像多线程,然而协程只有一个线程在执行

协作的标准
1.必须在只有一个单线程里实现并发
2.修改共享数据不需加锁
3.用户程序里自己保存多个控制流的上下文栈
4.一个协程遇到IO 操作自动切换到其它协程

协程创建方式1:
通过greenlet模块

from greenlet import greenlet

def sleep(name):
    print(f"{name}开始睡觉了...")
    g2.switch('曹操')
    print(f"{name}起床了...")
    g2.switch()
def eat(name):
    print(f"{name}开始吃饭了...")
    g1.switch()
    print(f"{name}吃完了...")
if __name__ == '__main__':
    g1 = greenlet(sleep)
    g2 = greenlet(eat)
    g1.switch('小乔')
小乔开始睡觉了...
曹操开始吃饭了...
小乔起床了...
曹操吃完了...

2.通过gevent模块
Gevent 是一个第三方库,可以轻松通过gevent 实现并发同步或异步编程,在gevent中用到的主要模式是Greenlet,它是以C 扩展模块形式接入Python 的轻量级协程。Greenlet 全部运行在主程序操作系统进程的内部,但他们被协作式地调度。
当一个greenlet遇到IO操作时,比如访问网络/睡眠等待,就自动切换到其他的greenlet,等到IO操作完成,再在适当的时候切换回来继续执行。由于IO操作非常耗时,经常使程序处于等待状态,有了gevent为我们自动切换协程,就保证总有greenlet在运行,而不是等待IO。同时也因为只有一个线程在执行,会极大的减少上下文切换的成本

import gevent

def sleep(name):
    print(f"{name}开始睡觉了...")
    gevent.sleep(1)
    print(f"{name}起床了...")

def eat(name):
    print(f"{name}开始吃饭了...")
    gevent.sleep(1)
    print(f"{name}吃完了...")

if __name__ == '__main__':
    g1=gevent.spawn(sleep, '小乔')
    g2=gevent.spawn(eat, '曹操')
    gevent.joinall([g1,g2])
小乔开始睡觉了...
曹操开始吃饭了...
小乔起床了...
曹操吃完了...

3.通过asyncio模块

import asyncio,time
async def fun1():
    for i in range(5):
        print("协程1")
        await asyncio.sleep(1)
# await 后跟一个可等待的对象
async def fun2():
    for i in range(5):
        print("携程2")
        await asyncio.sleep(2)
if __name__ == '__main__':
    start=time.time()
    asy_a = fun1()
    asy_b = fun2()
    #获取循环事件
    loop = asyncio.get_event_loop()
    #监听循环事件
    loop.run_until_complete(asyncio.gather(asy_a, asy_b))
    #关闭循环
    loop.close()
    end=time.time()
    print(f"总用时:{end-start}s")
协程1
携程2
协程1
携程2
协程1
协程1
携程2
协程1
携程2
携程2
总用时:10.010684967041016s

协程的嵌套:使用async可以定义协程,协程用于耗时的io操作,我们也可以封装更多的io操作过程,这样就实现了嵌套的协程,即一个协程中await了另外一个协程,如此连接起来。

import asyncio
import time
async def seed_to(x, y):
    print("老王你帮我算一下结果")
    result = await lao_w(x, y)
    print(f"结果为:{result}")

async def lao_w(x, y):
    print("好的,稍等一下")
    await asyncio.sleep(1)
    return x + y
if __name__ == '__main__':
    start=time.time()
    loop = asyncio.get_event_loop()
    loop.run_until_complete(seed_to(6, 8))
    loop.close()
    end=time.time()
    print(f"耗时:{end-start}s")
老王你帮我算一下结果
好的,稍等一下
结果为:14
耗时:1.0017786026000977s
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐