Python中的协程

目录

1.实现协程的方法

2.协程的意义

3.异步编程

3.1 事件循环

3.2 快速上手

3.3 await

3.4 Task对象

3.5 asyncio中的Future对象

  • 协程不是计算机提供,而是程序员人为创造
  • 协程(Coroutine),也可以被称为微线程,是一种用户态内的上下文切换技术,简而言之,其实就是通过一个线程实现代码块相互切换执行(用一个线程,在代码之间切换游走的执行)

1.实现协程的方法

  • greenlet(早期模块)
  • yield关键字
  • asyncio(python3.4)
  • async & await关键字

2.协程的意义

在一个线程中如果遇到IO等待时间,线程不会一直等待,而是利用空闲的时候再去干点其他事情

3.异步编程

3.1 事件循环

理解成为一个死循环,去检测并执行某些代码

# 伪代码
任务列表 = [任务1, 任务2,任务3,。。。。]

# 死循环
while True:
    可执行的任务列表,已完成的任务列表 = 去任务列表中检查所有的任务,将"可执行"和"已完成"的任务返回
    for 可执行任务 in 可执行的任务列表:
        执行可执行的任务
        
    for 已完成的任务 in 已完成的任务列表:
        在任务列表中移除 已完成的任务

示例代码

import asyncio

# 去生成或者获取一个事件循环
loop = asyncio.get_event_loop()
# 将任务放到‘任务列表’
loop.run_until_complete('任务')

3.2 快速上手

  • 协程函数,定义函数时候 async def 函数名
async def func():
    pass
  • 协程对象,执行协程函数()得到的协程对象
  • result = func()
  • 注意:执行协程函数创建协程对象,函数内部代码不会执行,如果执行协程函数代码,必须要将协程对象交给事件循环来处理

3.3 await

  • await + 可等待的对象(协程对象、Future、 Task对象)【可以理解为IO等待】
  • await 就是等待对应的值得到结果之后,再继续向下走
# 示例1
import asyncio

async def func():
    print("开始")
    response = await asyncio.sleep(2)
    print("结束", response)

asyncio.run(func())
"""
运行结果:
开始
(等两秒)
结束 None
"""
# 示例2
import asyncio

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

async def func():
    print("执行协程函数内部代码")
    # 遇到 IO 操作挂起当前协程(任务), 等IO操作之后再继续往下执行,当前协程挂起时候,
    # 事件循环可以去执行其他协程(任务)
    response = await others()
    print("IO请求结束,结束为:", response)

asyncio.run(func())
"""
执行协程函数内部代码
start
(等两秒)
end
IO请求结束,结束为: 返回值
"""
# 示例3
import asyncio

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

async def func():
    print("执行协程函数内部代码")
    # 遇到 IO 操作挂起当前协程(任务), 等IO操作之后再继续往下执行,当前协程挂起时候,
    # 事件循环可以去执行其他协程(任务)
    response = await others()
    print("IO请求结束,结束为:", response)
    
    response2 = await others()
    print("IO请求结束,结束为:", response2)

asyncio.run(func())

"""
运行结果:
执行协程函数内部代码
start
(等两秒)
end
IO请求结束,结束为: 返回值
start
(等两秒)
end
IO请求结束,结束为: 返回值
"""

3.4 Task对象

  • 在事件循环中添加多个任务
  • 立即将某个任务添加到事件循环
  • 在事件循环里面并发的创建多个任务,让事件循环遇到IO自动切换处理
  • Task用于并发调度协程,通过asyncio.create_task(协程对象)的方式创建Task对象
  • 注意:asyncio.create_task() 函数 在 python3.7中被加入,在python3.7之前, 可以改用低层级的asyncio.ensure_future()函数
import asyncio

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

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

async def main():
    print("main开始")
    
    # 创建Task对象,将当前执行func函数任务添加到事件循环
    task1 = asyncio.create_task(func1())
    # 创建Task对象,将当前执行func函数任务添加到事件循环
    task2 = asyncio.create_task(func2())
    print('main结束')

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

asyncio.run(main())
"""
运行结果:
main开始
main结束
1
1
(等两秒)
2
2
返回值 返回值
"""
# 示例2
import asyncio

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

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

async def main():
    print("main开始")
    
    task_list = [
        asyncio.create_task(func1()),
        asyncio.create_task(func2())
    ]
   
    print('main结束')

    # timeout : 最多等几秒
    # done -> 是一个集合
    done, pending = await asyncio.wait(task_list, timeout=None)
    print(done)
    
asyncio.run(main())
"""
main开始
main结束
1
1
(等两秒)
2
2
{ result='返回值'>,  result='返回值'>}

"""
# 实例3
import asyncio

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

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

task_list = [
    func1(),
    func2()
]
done, pending = asyncio.run(asyncio.wait(task_list))
print(done)
"""
1
1
(等两秒)
2
2
{ result='返回值'>,  result='返回值'>}

"""

3.5 asyncio中的Future对象

  • Task继承Future, Task对象内部await结果的处理基于Future对象来的
# 示例1
import asyncio

async def main():
    
    # 获取当前时间循环
    loop = asyncio.get_running_loop()

    # 创建一个任务(Future对象), 这个任务什么都不干
    fut = loop.create_future()
    
    # 等待任务最终结果(Future对象), 没有结果则会一直等下去。
    await fut

asyncio.run(main())
"""
运行结果:
因为没有结果,则程序一直会等下去
"""
import asyncio

async def set_after(fut):
    await asyncio.sleep(2)
    fut.set_result("666")

async def main():

    # 获取当前时间循环
    loop = asyncio.get_running_loop()

    # 创建一个任务(Future对象), 没绑定任何行为,则这个任务永远不知道什么时候结束
    fut = loop.create_future()

    # 创建一个任务(Task对象),绑定了 set_after 这个函数,函数内部在2s之后,会给fut赋值
    # 即手动设置,future 任务最终结果,那么fut就是可以结束了
    await loop.create_task(set_after(fut))
    
    # 等待任务最终结果(Future对象), 没有结果则会一直等下去。
    data = await fut
    print(data)

asyncio.run(main())
"""
运行结果:
两秒之后打印
666
"""

你可能感兴趣的:(Python进阶,Python,协程,async,await)