python异步任务协程yield greelet gevent asyncio async await高级使用

目录

一、什么是协程

二、协程实现方式

1. yield实现

2. greenlet实现

3. gevent实现

4. gevent-monkey补丁 

5. asyncio装饰器

6. async&await关键字

三、 asyncio使用

1. 相关概念

(1)event_loop(事件循环)

(2)coroutine function(协程函数)

(3)coroutine object(协程对象)

(3)Task(任务)

(4)Future

(5)async

(6)await

2. 运行一个协程对象

(1)方式1

(2)方式2

(3)方式3

(4)方式4

3. 协程并发执行

(1)asyncio.run()

(2)loop.run_until_complete

4. 并发等待

(1)wait

(2)gather

(3)wait_for

(4)as_completed

5. 获取协程返回值

(1)通过task.result()

 (2)通过add_done_callback()回调

6. 协程并发常用方式

(1)event_loop&asyncio.wait | asyncio.gather

(2)asyncio.run&asyncio.wait | asyncio.gather

(3)asyncio.run&asyncio.as_complete


一、什么是协程

协程(Coroutine),也可以被称为微线程,也称为用户级线程,是一种用户态内的上下文切换技术。在不开辟新线程的基础上完成多任务,其实就是通过一个线程实现代码间相互切换执行,在一个线程(协程)中,遇到io等待时间,线程可以利用这个等待时间去做其他事情。

并发的本质:切换+保存状态

cpu正在运行一个任务,会在两种情况下切走去执行其他的任务(切换由操作系统强制控制),一种情况是该任务发生了阻塞,另外一种情况是该任务计算的时间过长或有一个优先级更高的程序替代了它。

在Python中有多种方式可以实现协程,如下:

  • yield:生成器,借助生成器的特点可以实现协程代码;

  • greenlet:是一个第三方模块,用于实现协程代码,需要手动切换

  • gevent:基于greenlet实现的,遇到IO操作能够自动切换任务,等待IO操作完成,再在适当的时候切换回来继续执行;

  • asyncio:在Python3.4中引入的模块用于编写协程代码;

  • async & awiat:在Python3.5中引入的两个关键字,结合asyncio模块可以更方便的编写协程代码。

二、协程实现方式

1. yield实现

#!/usr/bin/python3
# -*- coding: utf-8 -*-
import time


# yield 实现协程
# 协程之间执行任务按照一定顺序交替执行
def task1():
    for i in range(5):
        print("---task1---", i)
        time.sleep(0.5)
        yield


def task2():
    for i in range(5):
        print("---task2---", i)
        time.sleep(0.5)
        yield


def main():
    t1 = task1()
    t2 = task2()
    while True:
        try:
            next(t1)
            next(t2)
        except StopIteration:
            break
    print("main finsh...")


if __name__ == '__main__':
    main()

运行结果:

---task1--- 0
---task2--- 0
---task1--- 1
---task2--- 1
---task1--- 2
---task2--- 2
---task1--- 3
---task2--- 3
---task1--- 4
---task2--- 4
main finsh... 

2. greenlet实现

#!/usr/bin/python3
# -*- coding: utf-8 -*-
import time

from greenlet import greenlet


def task1(num=5):
    for i in range(num):
        print("tak1----", i)
        # time.sleep(1)
        g2.switch()


def task2(num=5):
    for i in range(num):
        print("tak2----", i)
        time.sleep(1)
        g1.switch()


g1 = greenlet(task1)
g2 = greenlet(task2)
g1.switch()

输出结果:

tak1---- 0
tak2---- 0
tak1---- 1
tak2---- 1
tak1---- 2
tak2---- 2
tak1---- 3
tak2---- 3
tak1---- 4
tak2---- 4

3. gevent实现

#!/usr/bin/python3
# -*- coding: utf-8 -*-
import gevent
import time


def task(name, num):
    for i in range(num):
        print(gevent.getcurrent(), name, i)
        # 模拟一个耗时操作,注意不能使用time模块的sleep
        # time.sleep(1) # 顺序执行
        gevent.sleep(1) # 模拟耗时,遇到io操作切换到其他协程执行


def main():
    # spawn 方式创建协程
    g1 = gevent.spawn(task, 'task1...', 9)
    g2 = gevent.spawn(task, 'task2...', 5)
    g3 = gevent.spawn(task, 'task3...', 3)

    # d等待协程运行
    # g1.join()
    # g2.join()
    # g3.join()
    gevent.joinall([
        g1, g2, g3
    ])


if __name__ == '__main__':
    main()

运行结果如下:

<Greenlet at 0x19a1419c900: task('task1...', 9)> task1... 0
<Greenlet at 0x19a14338e00: task('task2...', 5)> task2... 0
<Greenlet at 0x19a1433d120: task('task3...', 3)> task3... 0
<Greenlet at 0x19a1419c900: task('task1...', 9)> task1... 1
<Greenlet at 0x19a14338e00: task('task2...', 5)> task2... 1
<Greenlet at 0x19a1433d120: task('task3...', 3)> task3... 1
<Greenlet at 0x19a1419c900: task('task1...', 9)> task1... 2
<Greenlet at 0x19a14338e00: task('task2...', 5)> task2... 2
<Greenlet at 0x19a1433d120: task('task3...', 3)> task3... 2
<Greenlet at 0x19a1419c900: task('task1...', 9)> task1... 3
<Greenlet at 0x19a14338e00: task('task2...', 5)> task2... 3
<Greenlet at 0x19a1419c900: task('task1...', 9)> task1... 4
<Greenlet at 0x19a14338e00: task('task2...', 5)> task2... 4
<Greenlet at 0x19a1419c900: task('task1...', 9)> task1... 5
<Greenlet at 0x19a1419c900: task('task1...', 9)> task1... 6
<Greenlet at 0x19a1419c900: task('task1...', 9)> task1... 7
<Greenlet at 0x19a1419c900: task('task1...', 9)> task1... 8

4. gevent-monkey补丁 

#!/usr/bin/python3
# -*- coding: utf-8 -*-
import gevent
import time
from gevent import monkey


monkey.patch_all()

def task(name, num):
    for i in range(num):
        print(gevent.getcurrent(), name, i)
        # 模拟一个耗时操作,注意不能使用time模块的sleep
        time.sleep(1) # 顺序执行


def main():
    gevent.joinall([
        gevent.spawn(task, 'task1...', 5),
        gevent.spawn(task, 'task2...', 5),
        gevent.spawn(task, 'task3...', 3)
    ])
    print("main finish...")


if __name__ == '__main__':
    main()

 运行结果:

<Greenlet at 0x22011992020: task('task1...', 5)> task1... 0
<Greenlet at 0x220119fd800: task('task2...', 5)> task2... 0
<Greenlet at 0x220119fd8a0: task('task3...', 3)> task3... 0
<Greenlet at 0x22011992020: task('task1...', 5)> task1... 1
<Greenlet at 0x220119fd800: task('task2...', 5)> task2... 1
<Greenlet at 0x220119fd8a0: task('task3...', 3)> task3... 1
<Greenlet at 0x22011992020: task('task1...', 5)> task1... 2
<Greenlet at 0x220119fd800: task('task2...', 5)> task2... 2
<Greenlet at 0x220119fd8a0: task('task3...', 3)> task3... 2
<Greenlet at 0x22011992020: task('task1...', 5)> task1... 3
<Greenlet at 0x220119fd800: task('task2...', 5)> task2... 3
<Greenlet at 0x22011992020: task('task1...', 5)> task1... 4
<Greenlet at 0x220119fd800: task('task2...', 5)> task2... 4
main finish...

5. asyncio装饰器

import asyncio

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


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


tasks = [
    asyncio.ensure_future(task1()),
    asyncio.ensure_future(task2())
]

loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))

运行结果:

1

3

2

4

6. async&await关键字

import asyncio


async def task1():
    for i in range(5):
        print("---task1---", i)
        await asyncio.sleep(0.5)


async def task2():
    for i in range(5):
        print("---task1---", i)
        await asyncio.sleep(0.5)

def main():
    loop = asyncio.get_event_loop()
    tasks = [
        asyncio.ensure_future(task1()),
        asyncio.ensure_future(task2())
    ]

    loop.run_until_complete(asyncio.wait(tasks))


if __name__ == '__main__':
    main()

运行结果:

---task1--- 0
---task1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值