协程不是计算机提供的机制,是程序员人为定义的。
协程被称为微线程,是一种用户态的上下文切换的技术。
简而言之就是通过一个线程实现代码块相互切换运行。
线程执行任务时 遇到IO耗时操作 不会再等待 而是去执行其他工作
from greenlet import greenlet def fun(): print(111) gr2.switch() print(222) gr2.switch() def fun1(): print(33) gr1.switch() print(44) gr1 = greenlet(fun) gr2 = greenlet(fun1) gr1.switch()
# 创建生成器函数 def fun1(): yield 1 yield from fun2() yield 2 def fun2(): yield 3 yield 4 f = fun1() for item in f: print(item)
python3.5版本后才可以使用
import asyncio async def func1(): print(1) # 网络IO请求 下载一张图片 await asyncio.sleep(2) # 遇到类似IO耗时操作 自动切换到task中的其他任务 print(2) async def func2(): print(33) # 网络IO请求 下载一张图片 await asyncio.sleep(2) # 遇到IO耗时操作,自动化切换到task中的其他操作 print(444) tasks = [asyncio.ensure_future(func2()), asyncio.ensure_future(func1())] loop = asyncio.get_event_loop() loop.run_until_complete(asyncio.wait(tasks))
按顺序执行 遇到耗时操作时执行其他任务
结果 33 1 444 2
理解成一个死循环,去检测并执行某些代码
# 伪代码 任务列表=[任务1,任务2,任务3] while true: 可执行的任务列表(比如IO请求完毕剩下其余逻辑),已完成的任务列表(任务代码全部完成) = 去任务列表中检查所有的任务 将可执行和已完成的任务返回 for 可执行任务 in 可执行的任务列表: 执行可执行的任务 for 已完成的任务 in 已完成的任务列表: 在任务列表中移除已经完成的任务 如果任务列表中的任务都已完成 则终止循环
import asyncio #去生成或获取一个事件循环 loop = asynio.get_event_loop() #将任务放到任务列表 (在任务列表中自动检测任务状态) loop.run_util_complete(任务)
函数名前面有async 关键字的函数
协程对象 执行协程函数得到的对象
# 协程函数 async def func(): print (111) # 协程对象 result = func()
协程对象的内部代码不会执行
如果要执行 需要交给事件循环来处理
import asyncio async def func(): print(111) result = func() # loop = asyncio,get_event_loop() # loop.run_until_complete(result) asyncio.run(result) # python3.7以后
await+可等待对象(协程对象,Future,Task对象-》IO等待)
import asyncio async def func(): print ("xxx") response = await asyncio.sleep(2) print("结束",response) asyncio.run(func())
await 就是等待对象的值得到结果之后再继续向下走
在事件循环中添加多个任务的。
示例1
import asyncio async def func(): print(111) await asyncio.sleep(2) print(222) async def main(): print("main开始") # 创建task任务 并将task 任务添加到事件循环 task1 = asyncio.create_task(func()) task2 = asyncio.create_task(func()) ret1 = await task1 ret2 = await task2 print(ret1, ret2) asyncio.run(main())
示例2
import asyncio async def func(): print(111) await asyncio.sleep(2) print(222) async def main(): print("main开始") # 创建task任务 并将task 任务添加到事件循环 task1 = asyncio.create_task(func(),name="task1") task2 = asyncio.create_task(func(),name = "task2") task_list = [task1, task2] # 返回值都放在done集合中,pending 执行过程中部分返回值放在pending中 done, pending = await asyncio.wait(task_list) print(done) asyncio.run(main())
task对象基于future future如果不被赋值 将一直执行不会终止 但task一般绑定一个函数,函数执行完自动赋值 也自动终止。
使用线程池 进程池实现异步时使用的对象
如果做异步编程时 遇到了某个第三方模块不支持协程时 使用下面这种方式
异步和非异步结合案例
class Reader(object): """自定义异步迭代器(同是也是异步可迭代对象)""" def __init__(self): self.count = 0 async def readline(self): self.count +=1 if self.count ==100: return None return self.count def__aiter__self(self): return self async def __anext__(self): val = await self.readline() if val == None: raise StopAsyncIteration return val async def func(): obj = Reader() #async for 循环只能在异步函数中使用 async for item in obj: print(item) asyncio.run(func())
是asyncio循环的替代方案,事件循环>默认的asyncio的事件循环
效率提升至少一倍
django3和fastapi内部就是使用的uvloop 所以快 支持 异步
在使用代码操作redis时,链接、操作、断开都是网络IO
同时使用两台服务器的redis 在连接第一台服务器的时候去做连接第二台服务器的任务,
pip install aiomysql