目录
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 """