写这篇笔记的初衷:由于现在ai大火,在agent学习,开发的时候几乎都离不开异步编程,但是网络上对于异步编程的讲解要么就是比较简略,要么就是比较晦涩难懂。很幸运的看到了一门比较优质的网课,这里就把我在看网课时记录和总结的笔记分享出来,都是自己纯手动整理的,包含了很丰富的代码实例,供大家一起交流学习。喜欢的话点个赞吧~
目录
协程
协程,简而言之,就是通过一个线程实现代码块相互切换执行。
协程的意义:在一个线程中如果遇到IO等待时间,线程不会傻傻等,利用空闲时间再去干点其他事
实现协程的几种方法:
- yield关键字
- asyncio装饰器(3.4版本)
- async,await关键字(3.5版本后,推荐使用)
1.yield关键字
def func1():
yield 1;
yield from func2() #跳到func2函数里面
yield 2
def func2():
yield 3
yield 4
f1=func1()
for item in f1:#每次循环,执行里面的yield
print(item)
如果一个函数里面有yield关键字,我们就认为是生成器函数,只要执行函数,返回的就是生成器
但是在真正实现协程,我们不会用这种方式,这里了解即可。
2.asyncio装饰器(3.4版本)
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))
asyncio模块的特别之处在于遇到了yield from后面的IO操作,它不会傻傻地等,它会切换任务
实际应用:比如我要下载很多图片,在发送下载一张图片的请求后等待响应的时候,线程可以继续发送其它下载图片的请求,这时就可以节省很多时间
3.async,await关键字(3.5版本后,推荐使用)
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))
这个完成的功能和asyncio装饰器其实是一样的,本质上就是把装饰器和yield from换成async 和 await,更加方便使用而已
事件循环
伪代码:
任务列表=[任务1,任务2...]
while True:
for 可执行的任务 in 可执行的任务列表
执行已就绪的任务
for 已完成的任务 in 已完成的任务列表
在任务列表中移除已完成的任务
如果任务中的任务都完成,就终止循环
import asyncio
#去生成获取一个事件循环
loop=asyncio.get_event_loop()
#将任务放到任务列表
loop.run_until_complete(任务)
协程函数,定义函数时候 async def 函数名
协程对象,执行 协程函数()得到的协程对象
async def func():
pass
result=func() #这个result就是协程对象,但是func函数里面是不会执行的
loop=asyncio.get_event_loop()
loop.run_until_complete(result)
#3.7之后
asyncio.run(result)
如果想要运行协程函数内部代码,必须要将协程对象交给事件循环
await
await+可等待的对象(协程对象,Future,Task对象,IO等待)
示例1:
async def func():
response=await asyncio.sleep(1)
print("over")
return "返回值"
asyncio.run(func())
示例2:
async def others():
await asyncio.sleep(1)
print("over")
return "返回值"
async def func():
response=await others()#await+协程对象
print("IO请求结束,结果为:",response)
asyncio.run(func())
遇到IO操作挂起当前协程,等IO操作结束之后继续往下执行,当前协程挂起时,事件循环可以去执行其他任务示例3:(await+多个任务)
async def others():
await asyncio.sleep(1)
print("over")
return "返回值"
async def func():
response1=await others()#await+协程对象
print("IO请求结束,结果为:",response1)
response2=await others()#await+协程对象
print("IO请求结束,结果为:",response2)
asyncio.run(func())
这里一定要注意,await其实就是在等,一定要等await后面的函数执行完成了,返回值了,才会执行下一句
Task对象
帮助在事件循环中添加多个任务
Task用于并发协程调度,通过asyncio.create_task(协程对象)(3.7之后)的方式创建Task对象,这样可以让协程加入事件循环中等待被调度执行。
示例1:
async def func():
await asyncio.sleep(1)
print("over")
return "返回值"
async def main():
#创建task对象,将当前执行的func函数任务添加到事件循环
task1=asyncio.create_task(func())
task2=asyncio.create_task(func())
ret1=await task1 #这里执行task1的时候,进入func函数,遇到IO(asyncio.sleep())的时候,会切换到另一个任务task2
ret2=await task2
示例2(常写):
async def func():
response=await asyncio.sleep(1)
print("over")
return "返回值"
async def main():
#创建task列表,将task对象都加到列表里面
task_list=[
asyncio.create_task(func())
asyncio.create_task(func())
]
done,pending=await asyncio.wait(task_list) #注意这里不能直接写 await task_list
#done是一个集合,里面是task对象的返回值
asyncio.run(main())#这里事件循环已经创建了
Future对象
Task继承Future,Task对象内部await的结果是基于Future对象来的
示例1:
async def main():
#获取当前事件循环
loop=asyncio.get_running_loop()
#创建一个任务,future对象,这个任务什么也不干
fut=loop.create_future()
#等待任务最终结果(Future对象),没有结果则会一直等下去
await fut
future对象用于等待结果
示例2:
async def set_after(fut):
await asyncio.sleep(2)
fut.set_result("1")#给future对象设置值,那么await就不再等待了
async def main():
#获取当前事件循环
loop=asyncio.get_running_loop()
#创建一个任务,future对象,这个任务什么也不干
fut=loop.create_future()
await loop.create_task(set_after(fut))
#等待任务最终结果(Future对象),没有结果则会一直等下去
data=await fut
uvloop
是asyncio的事件循环的替代方案,它的效率大于asyncio的效率
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())#将前面的替换成括号里的
#后面的代码和之前写代码的逻辑一致
uvicorn效率之所以高,本质上内部用的是uvloop
到这里就结束了,希望这篇笔记能帮助到大家,喜欢的话点个关注吧,我以后会继续分享相关知识的~
&spm=1001.2101.3001.5002&articleId=163199031&d=1&t=3&u=ed5273ecc1ac42e2baac755faafba6e9)
2408

被折叠的 条评论
为什么被折叠?



