1. 协程

0. greenlet,在此不予介绍

1. yield,在此也不介绍

2. asyncio

1. asyncio是python3.4后推出的协程库

2. 协程函数必须通过一下形式运行

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

3. asyncio遇到IO阻塞自动切换,遇到IO就自动切换,以下函数的asyncio模拟IO请求,但如果是真正的IO请求,比如网络IO请求,那么意义重大

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))

3. async & await关键字

1. 在python3.5版本以后实现的,跟asyncio一样,但是使用更简便,不用装饰器

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))

2. 协程的意义

在一个线程中,如果遇到IO等待时间,线程不会傻傻等,利用空闲时间再去干点其他事。

3. 异步编程

1. 事件循环

可以理解成为一个死循环,去检测并执行某些代码
16292-ka9lr6fikj.png

2. 快速上手

协程函数:定义函数时用async def 函数名

协程对象:执行协程函数()得到的协程对象

async def func():
  pass

result = func()  # 这时候func不会运行,只是生成了func协程对象

注意:执行协程函数创建协程对象,函数内部代码不会执行

要是想运行得借助事件循环,必须要将协程对象交给事件循环来处理:

import asyncio

async def func():
    print("tcl!!!")

result = func()  # 这时候func不会运行,只是生成了func协程对象

# 去生成或获取一个事件循环
loop = asyncio.get_event_loop()

# 将任务放到任务列表
loop.run_until_complete(result)

然而这样还是太麻烦了,在python3.7以后,可以直接这样写:

import asyncio

async def func():
    print("tcl!!!")

result = func()  # 这时候func不会运行,只是生成了func协程对象

asyncio.run(result)

3. await

awit后跟可等待对象(写成对象、Future、Task对象 -> IO等待)

示例一:

import asyncio

async def func():
    print("hello async!!!")
  # IO等待
    response = await asyncio.sleep(2)
    print("wait over:", response)


asyncio.run(func())

示例二:

import asyncio


async def others():
    print("start")
    await asyncio.sleep(2)
    print("end")
    return '返回值'

async def func():
    print("执行协程函数内部代码")

    response = await others()

    print("IO请求结束,结果为:", response)


asyncio.run(func())

执行结果:
50531-q1f0hkyc0w.png

示例三:

import asyncio


async def others():
    print("start")
    await asyncio.sleep(2)
    print("end")
    return '返回值'

async def func():
    print("执行协程函数内部代码")

    response1 = await others()
    print("IO请求结束,结果为:", response1)

    response2 = await others()
    print("IO请求结束,结果为:", response2)

asyncio.run(func())

await就是等待,等待对应对象的值得到结果之后再往下走,并不是说性能没有优化,而是在一个await等待过程中会去执行其他任务

4. Task对象

白话:在事件循环中添加多个任务,一个任务遇到IO后去执行其他任务

Tasks用于并发调度协程,通过asyncio.create_task(协程对象)的方式创建Task对象,这样可以让协程加入事件循环中等待被调度执行。除了使用asyncio.create_task()函数以外,还可以用低层级的loop.create_task()ensure_future()函数。不建议手动实例化Task对象

注意:asyncio.create_task()函数是在python3.7中被加入,在3.7之前,可以使用低层级的asyncio.ensure_future()函数

示例一:

import asyncio

async def func():
    print(1)
    await asyncio.sleep(2)
    print(2)
    return "返回值"

async def main():
    print("main开始")

    # 创建Task对象,将当前执行func函数任务添加到事件循环
    task1 = asyncio.create_task(func())

    task2 = asyncio.create_task(func())

    print("main结束")

    # 当执行某协程遇到IO操作时,会自动切换执行其他任务
    # 此处的await是等待相对应的协程全部执行完毕并获取结果
    ret1 = await task1
    ret2 = await task2

    print(ret1, ret2)

asyncio.run(main())

示例二:

import asyncio

async def func():
    print(1)
    await asyncio.sleep(2)
    print(2)
    return "返回值"

async def main():
    print("main开始")

    # 创建Task对象,将当前执行func函数任务添加到事件循环
    task_list = [
        asyncio.create_task(func()),
        asyncio.create_task(func()),
    ]

    print("main结束")

    down, pending = await asyncio.wait(task_list)

    print(down)

asyncio.run(main())

示例三:将task放在函数外边,还没有创建事件循环,所以task只能放协程对象,在asyncio.wait内部生成事件循环后内部创建Task对象

import asyncio

async def func():
    print(1)
    await asyncio.sleep(2)
    print(2)
    return "返回值"

task_list = [
    func(),
    func(),
]

done, pending = asyncio.run(asyncio.wait(task_list))
print(done)

5. Future对象

是一个更低级的接口,等待异步的结果

Task继承Future,Task对象内部await结果的处理基于Future对象

最后修改:2022 年 04 月 24 日
如果觉得我的文章对你有用,请随意赞赏