2020.11.4/协程:yield/send/,greenlet 异步IO:gevent/asyncio

28 篇文章 0 订阅

协程

1.协程,又称微线程,纤程。英文名Coroutine。
协程看上去是函数,但执行过程中,在函数内部可中断,然后转而执行别的函数,在适当的时候再返回来接着执行。
python可以通过 yield/send 的方式实现协程,也可以使用第三方库中的greenlet来实现协程。

2.协程的优势
协程的特点在于是一个线程执行。
所以协程最大的优势就是极高的执行效率。因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显。
第二大优势就是不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在协程中控
制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。*

生产者-消费者模型

#消费者
def consumer():
    r = ''
    while True:
        n = yield 
		
        print('[CONSUMER] Consuming %s...' % n)
#生产者 
def produce(c):
    c.send(None)
    for n in range(1, 6):
        print('[PRODUCER] Producing %s...' % n)
        r = c.send(n)
    c.close()
 
c = consumer()
produce(c)

在这里插入图片描述

使用greenlet实现生产者/消费者模型

from greenlet import greenlet
 
def consumer():
    while True:
        n = gr_produce.switch()
        print('[CONSUMER] Consuming %s...' % n)
 
def produce():
    for n in range(1, 6):
        print('[PRODUCER] Producing %s...' % n)
        gr_consumer.switch(n)
 
gr_consumer = greenlet(consumer)
gr_produce = greenlet(produce)
 
#切换到consumer中运行
gr_consumer.switch()

协程的缺陷

1.无法利用多核资源:协程的本质是个单线程,它不能同时将 单个CPU 的多个核用上,协程需要和进程配合才能运行在多CPU上。当然我们日常所编写的绝大部分应用都没有这个必要,除非是cpu密集型应用。
2.进行阻塞(Blocking)操作(如IO时)会阻塞掉整个程序。

同步IO/异步IO

同步IO操作:导致请求进程阻塞,直到IO操作完成。
异步IO操作:不导致进程阻塞。
python实现异步IO的库:
gevent
asyncio

gevent

greenlet已经实现了协程,但是这个还的人工切换,是不是觉得太麻烦了,不要捉急,python还有一个比greenlet更强大的并且能够自动切换任务的模块gevent
其原理是当一个greenlet遇到IO(指的是input output 输入输出,比如网络、文件操作等)操作时,比如访问网络,就自动切换到其他的greenlet,等到IO操作完成,再在适当的时候切换回来继续执行。
由于IO操作非常耗时,经常使程序处于等待状态,有了gevent为我们自动切换协程,就保证总有greenlet在运行,而不是等待IO
安装方式
使用如下命令安装gevent模块:
pip3 install gevent


gevent的基本使用方法


*gevent.spawn(func, args, …)方法用来生成协程,他接受一个函数作为参数
gevent.joinall([t1, t2, …])方法用来启动协程轮询并等待运行结果
gevent.sleep()用来模拟一个IO操作,阻塞后自动切换到另一个协程执行

实例代码-遇到IO阻塞自动切换

import gevent
 
def task1():
    print('[TASK1] Begin')
    gevent.sleep(8)
    print('[TASK1] End')
 
def task2():
    print('---[TASK2] Begin')
    gevent.sleep(3)
    print('---[TASK2] End')
 
def task3():
    print('------[TASK3] Begin')
    print('------[TASK3] End')
 
gevent.joinall([
        gevent.spawn(task1),
        gevent.spawn(task2),
        gevent.spawn(task3)
])

在这里插入图片描述

asyncio

asyncio是Python 3.4版本引入的标准库,直接内置了对异步IO的支持。
asyncio的编程模型包含两个重要的点:
coroutines(协程):交给 asyncio 执行的任务,称为协程(coroutine)。
event loop(事件循环):然后把需要执行的协程放到event loop中执行, event loop负责监测和事件触发等处理工作。当某一协程遇到阻塞等待读取或者写入数据的时候, 进行上下文的切换,把运行机会让给其他协程,从而让执行效率最大化。


asyncio编程模型

协程的定义,需要使用 async def 语句。
async def do_some_work(x):
asyncio.sleep(x)
asyncio.sleep(x) 用来模拟实际的IO操作,await asyncio.sleep(x) 就是等待这个IO操作的结束,这个过程会发生阻塞,从而导致协程切换。
协程定义好了之后还需要使用 ensure_future() 函数把协程对象包装成了future对象
asyncio.gather将多个Future进行封装成一个Future队列
主程序中通过 asyncio.get_event_loop() 得到一个标准的事件循环
时间循环提供一个 run_until_complete() 方法,它接收asyncio.gather封装好的Future队列来运行 loop ,直到所有的future完成

实例代码 - 遇到阻塞自动切换

import asyncio
 
async def task1():
    print('[TASK1] Begin')
    await asyncio.sleep(8)
    print('[TASK1] End')
 
async def task2():
    print('---[TASK2] Begin')
    await asyncio.sleep(3)
    print('---[TASK2] End')
 
async def task3():
    print('------[TASK3] Begin')
    print('------[TASK3] End')
 
tasks = asyncio.gather(asyncio.ensure_future(task1()),
 asyncio.ensure_future(task2()),
 asyncio.ensure_future(task3()))
loop = asyncio.get_event_loop()
loop.run_until_complete(tasks)
loop.close() 

在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值