python协程与异步协程

 在前面几个博客中我们一一对应解决了消费者消费的速度跟不上生产者,浪费我们大量的时间去等待的问题,在这里,针对业务逻辑比较耗时间的问题,我们还有除了多进程之外更优的解决方式,那就是协程和异步协程。在引入这个概念之前我们先看   看这个图:  

从这个图片我们可以看出来,假如来了9个任务,即使我们开了多进程,在业务的执行过程中我们依旧是同步操作,所以执行完这一波任务我们一共需要9s,虽然比单进程快了3倍,但是在机器条件可以(肯定可以)的情况下,我们如何更加合理的利用给我们的资源呢?于是异步协程的优势就来了:

根据这张图我们可以看出来,在任务1执行完业务逻辑1的时候,任务2就可以开始执行,这样当任务2执行完业务逻辑1的时候,任务3就开始执行了,这样我们3个进程,总共耗时只需要5s,比上面同步的方式快了足足4s,省去了等待的时间,让模块之间衔接和调用更加充分。

在python中,我们先介绍一下2.0的协程:gevent的使用,在python3.4之后添加了syncoio的使用,这篇博客我们就专门针对业务逻辑部分进行深度的优化:

gevent是第三方库,通过greenlet实现协程,其基本思想是:

当一个greenlet遇到IO操作时,比如访问网络,就自动切换到其他的greenlet,等到IO操作完成,再在适当的时候切换回来继续执行。由于IO操作非常耗时,经常使程序处于等待状态,有了gevent为我们自动切换协程,就保证总有greenlet在运行,而不是等待IO(引用)。

比如下面代码:

from gevent import monkey

monkey.patch_all()

import gevent
import time


# TODO 此处是业务逻辑操作
def logicDel(data):
    time.sleep(2)
    print('im running', data)


if __name__ == '__main__':
    # 在这里我们声明几个任务,把任务放到一个list中去做分配调度
    tasks = [gevent.spawn(logicDel, data) for data in range(9)]
    gevent.joinall(tasks)

我们可以看到我们在一个tasks里面9个任务,每个任务执行都要sleep2秒,如果是阻塞式运行就需要18s,但是我们加入了协程,所有的任务完成只需要2s,其中原理和上图(异步加载图)一样,这里就不赘述了。

然而有时候我们代码业务逻辑中一个业务执行不只有一个任务,其中每个任务之间还有调度依赖的关系,这时候我们的gevent就显得有点力不从心了,这里就引进了python3.4之后的一个自带的包asyncio——异步协程。

asyncio的编程模型就是一个消息循环。我们从asyncio模块中直接获取一个EventLoop的引用,然后把需要执行的协程扔到EventLoop中执行,就实现了异步IO。用asyncio实现Hello world代码如下:

import threading
import asyncio


@asyncio.coroutine
def hello():
    print('Hello world11111111 (%s)' % threading.currentThread())
    yield from asyncio.sleep(1)
    print('Hello again22222222 (%s)' % threading.currentThread())


loop = asyncio.get_event_loop()
tasks = [hello(), hello()]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()

其中每个tasks都是非阻塞式的,当然这个还是没有解决一个业务有多个任务且每个任务之间存在依赖关系应当怎么解决的问题,因为我们还没有引用async await:

import asyncio
import time


# Borrowed from http://curio.readthedocs.org/en/latest/tutorial.html.
# @asyncio.coroutine
async def myslep(n):
    print(n)
    time.sleep(10)
    asyncio.sleep(5)


async def countdown(number, n):
    while n > 0:
        print('T-minus', n, '({})'.format(number))
        # await myslep(n)
        tasks2 = []
        await asyncio.ensure_future(myslep(n))
        # time.sleep(2)
        n -= 1


loop = asyncio.get_event_loop()
tasks = [
    asyncio.ensure_future(countdown("A", 2)),
    asyncio.ensure_future(countdown("B", 3)),
    asyncio.ensure_future(countdown("C", 3)),
]

loop.run_until_complete(asyncio.wait(tasks))

loop.close()

猜你喜欢

转载自blog.csdn.net/qq_38839677/article/details/82259761