python中的协程,异步编程async,await
一、什么是协程
理解协程:https://www.cnblogs.com/liyuanhong/articles/14268571.html
二、实现协程的几种方法
- greenlet ,早期模块
- yield关键字
- asyncio装饰器(python3.4)
- async、await 关键字(python3.5)
2.1 greenlet 实现协程
from greenlet import greenlet def test1(): print(1) # 第二步,输出1 gr2.switch() # 第三部,切换到test2 print(2) # 第六部,输出2 gr2.switch() # 第七部,切换到test2 def test2(): print(3) # 第四部,输出3 gr1.switch() # 第五部,切换到test1 print(4) # 第八步,输出4 gr1 = greenlet(test1) gr2 = greenlet(test2) gr1.switch() # 第一步,去执行test1函数
执行结果:

2.2 yield去实现协程
def test1(): yield 1 yield from test2() yield 2 def test2(): yield 3 yield 4 f = test1() for i in f: print(i)
执行结果:

2.3 asyncio 实现协程(python3.4 以及之后的版本可用)
注意:对基于生成器的协程的支持已被弃用,并在Python 3.11中被删除,所以一下代码会在@asyncio.coroutine 报错,因此,您需要在def之前使用**async关键字**,详见2.4的代码
import asyncio @asyncio.coroutine def test1(): print(1) yield from asyncio.sleep(2) # 遇到熊等待,自动化切换到task其他任务 print(2) @asyncio.coroutine def test2(): print(3) yield from asyncio.sleep(2) # 遇到熊等待,自动化切换到task其他任务 print(4)
task = [
asyncio.ensure_future(test1()),
asyncio.ensure_future(test2())
]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(task))
2.4 async 与 await 关键字
import asyncio async def test1(): print(1) await asyncio.sleep(2) # 遇到熊等待,自动化切换到task其他任务 print(2) async def test2(): print(3) await asyncio.sleep(2) # 遇到熊等待,自动化切换到task其他任务 print(4) task = [ asyncio.ensure_future(test1()), asyncio.ensure_future(test2()) ] loop = asyncio.get_event_loop() loop.run_until_complete(asyncio.wait(task))
执行结果

三、asyncio 事件循环
3.1事件循环
什么是事件循环:可以理解为一个死循环,去检测并执行某些代码。如下伪代码:
任务列表 = [任务1,任务2,任务3,...] while Ture: 可执行的任务列表,已完成任务列表 = 去任务列表中查询所有的任务,将可执行任务和已完成任务返回 for 就绪任务 in 可执行的任务列表: 执行已就绪任务 for 已完成任务 in 已完成任务列表: 在任务列表中一次已完成的任务 如果任务列表中的任务都已完成,则终止循环
import asyncio # 去获取一个事件循环 loop = asyncio.get_event_loop() # 将任务放到任务列表 loop.run_until_complete(asyncio.wait(task))
四、协程函数与协程对象
协程函数,定义函数使用: async def 函数名。
协程对象,执行协程函数,得到的对象就是协程对象。(执行协程函数,内部代码不会执行,只会得到一个协程对象)
async def test(): print("hello") ob = test() # 执行协程函数,得到一个协程对象,函数内部代码不会执行 print(ob)
执行结果

如果要执行协程函数,需要用事件循环去执行协程函数
import asyncio async def test(): print("hello") ob = test() # 使用事件循环去执行协程函数 loop = asyncio.get_event_loop() loop.run_until_complete(ob)
执行结果:

在python3.7以后会有更加简便的写法:
import asyncio async def test(): print("hello") ob = test() # python3.7以后可以使用这种简便写法 asyncio.run(ob)
五、await 关键字
await后面一般跟一个可等待的对象(协程对象、future对象、Task对象 -> IO等待)
import asyncio async def eat(): print("走吃饭") await asyncio.sleep(2) # 遇到IO等待会自动切换其他任务 print("饭吃完了") return "完成" async def main(): print("main start") # 创建task对象 task1 = asyncio.create_task(eat()) task2 = asyncio.create_task(eat()) print("main end") # 遇到IO等待会自动切换其他任务 res1 = await task1 res2 = await task2 print(res1,res2) asyncio.run(main())
执行结果:

上面的代码一般会按照下面的方式去写:
import asyncio async def eat(): print("走吃饭") await asyncio.sleep(2) # 遇到IO等待会自动切换其他任务 print("饭吃完了") return "完成" async def main(): print("main start") # 创建task对象 task_list = [ asyncio.create_task(eat()), asyncio.create_task(eat()) ] print("main end") # asyncio.wait返回两个值,默认任务列表的返回值都会放到done里 done,pendding = await asyncio.wait(task_list) print(done) print(done.pop().result()) asyncio.run(main())
执行结果如下:

六、Task对象
Task对象用于并发调度协程,通过asyncio.create_task(协程对象) 的方式创建Task对象(在python3.7中加入的该函数)。这样可以让协程加入事件循环中等待调度执行。除了使用asyncio.create_task函数以外,还可以使用低层级的loop.create_task()或 ensure_future()函数,不建议手动实例化Task对象。
七、异步上下文管理器
对象通过定义 __aenter__ ()和 __aexit__() 方法来对 async with 中的环境进行控制。
async with 不能单独存在,必须嵌套到一个协程函数中才能使用,否则会报错,例如:
import asyncio class AsynConnectDb(): def __init__(self): self.conn = None async def do_something(self): print("操作数据库") return "返回结果" async def __aenter__(self): print("连接数据库") await asyncio.sleep(1) return self async def __aexit__(self, exc_type, exc_val, exc_tb): print("数据库连接断开") await asyncio.sleep(1)
# async with 不能单独存在,必须嵌套到一个协程函数中才能使用 async def func(): async with AsynConnectDb() as db: result = await db.do_something() print(result) asyncio.run(func())
运行结果:

八、异步迭代器
什么是异步迭代器
实现了 __aiter__() 和 __anext__() 方法的对象。__anext__()必须返回一个 awaitable 对象。async for 会处理异步迭代的 __anext__()方法返回的可等待对象。知道引发一个StopAsyncIteration异常。
什么事异步迭代对象
可在 async for 语句中使用的对象。必须通过它的__aiter__()方法返回一个 asynchronous iterator。
async for不能单独存在,必须嵌套到一个协程函数中才能使用,否则会报错,例如:
import asyncio class Reader(): def __init__(self): self.count = 0 async def readLine(self): await asyncio.sleep(1) self.count += 1 if self.count == 5: return None return self.count def __aiter__(self): return self async def __anext__(self): val = await self.readLine() if val == None: raise StopAsyncIteration return val
# async for不能单独存在,必须嵌套到一个协程函数中才能使用 async def func(): async for item in Reader(): print(item) asyncio.run(func())
运行结果:

 
                    
                
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号