"""
python异步携程编程
什么是协程?
1、携程是可以暂停运行 也可以恢复执行的函数,通过async def 定义,
他和普通函数不一样的地方是,它在执行时不会真的执行里面的代码
而是返回一个协程对象,在执行协程对象时 才会执行里面的代码,
2、当出现await时,协程会暂停运行,让出控制权,
等await完成了在请求控制权恢复运行
3、拥有控制权的协程能运行,没有控制权的协程只能等待
什么是事件循环?
事件循环主要做几件事如下:
1、第一步 检查携程,拿到控制权后检查有没有可以执行的协程
2、第二步 让出控制,将控制权传递给可以执行的协程
3、第三步 等待协程,等当前协程暂停或者运行完,放开控制权给自己,然后在回到第一步
问题:事件循环怎么能知道哪些协程可以执行,哪些协程不可以执行呢?
答: 通过任务,任务是对协程的封装,除了包含协程本身还记录了协程的状态,
例如准备执行,正在运行,已完成等等
让事件循环知道,当前协程能不能够执行,只要一个协程被包装成任务了,
他就会被事件循环调度执行
什么是任务?
任务是包含协程的task,创建任务有两种方式
1、手动创建任务,适合可以在中途对任务做一些其他的操作
task=asyncio.create_task( 协程函数() )
2、自动创建任务并返回结果,不需要对任务中途进行处理的场景,
2.1 实现方式一
如下可以一起执行多个协程函数,当所有协程函数都执行完了,
就返回结果列表,结果获取的顺序和传入顺序是一样的
asyncio.gather(协程函数1(),协程函数2(),协程函数3())
通过await来等待获取结果列表,并获取到结果
result= await asyncio.gather(协程函数1(),协程函数2(),协程函数3())
2.2 实现方式二
as_completed 的输入参数是 包含协程的可迭代对象
返回参数是一个迭代器,迭代器会按照协程完成的顺序依次返回已完成的协程
results=asyncio.as_completed([协程函数1(),协程函数2()])
使用await可以返回已完成的协程结果
for result in results:
print(await result)
2.3 区别:asyncio.gather,与asyncio.as_completed区别是
前者gather是把所有协程都执行完再返回结果列表
后者as_completed是执行完了一个协程结果就返回一个
使用建议:
如果你想执行完了立即处理结果 as_completed会更适合你
await关键字?
1、await关键字是让出当前协程控制权,暂停当前携程执行,
2、await关键字只能出现在协程函数中,非协程函数无法使用,
必须是async def 的函数
三、案例 异步执行 模拟 网络读取文件,解析文件两个函数
1、定义协程函数,async def 、在函数内需要暂停的地方可以使用await,
但是要注意 await暂停后面的代码也要执行 需要使用协程 例如asyncio.sleep(1)
2、把协程包装成任务
task1=asyncio.create_task( 协程函数() )
3、建立事件循环
把任务交给事件循环管理
asyncio.run(task1)
"""
import asyncio
from time import perf_counter
#定义协程函数 在需要暂停的地方
async def fetch_url(url):#请求url 模拟网络请求
print("开始执行 fetch_url")
# 使用await暂停当前携程,等sleep完成了在来执行
# 但是让谁来执行sleep呢?答案是让协程来执行所以使用asyncio.
# 所以我们把 sleep 修改为 asyncio.sleep
# 一会我们还会把 函数包装成任务
# 因为只有把协程包装成任务了 才能让事件去执行监听
await asyncio.sleep(1)
print("完成执行 fetch_url")
return "url_content";
async def read_file(file_path):
print("开始执行 read_file")
# 使用await暂停当前携程,等sleep完成了在来执行
# 但是让谁来执行sleep呢?答案是让协程来执行所以使用asyncio.
# 所以我们把 sleep 修改为 asyncio.sleep
# 一会我们还会把 函数包装成任务
# 因为只有把协程包装成任务了 才能让事件去执行监听
await asyncio.sleep(1)
print("完成执行 read_file")
return "file_content"
async def main():
url="www.baidu.com"
file_path="./test.txt"
#把协程请求函数包装成任务
task1=asyncio.create_task(fetch_url(url))
#把协程读取文件函数包装成任务
task2=asyncio.create_task(read_file(file_path))
#获取到携程函数的返回值,使用await
url_content=await task1
file_content=await task2
print(url_content)
print(file_content)
if __name__ == '__main__':
#记录开始时间
start_time=perf_counter()
#创建事件循环,把协程放入事件循环中
asyncio.run(main())
end_time=perf_counter()
print("执行时间:",end_time-start_time)