协程:
1:是一种线程内部的任务调度机制,通过事件循环实现任务的挂起与恢复执行
本质就是一个先处理,遇到IO操作时,不让CPU等待,把CPU交给其他任务
注意1:
协程不是操作系统提供的,CPU并不能看见协程
操作系统并不知道协程的存在
协程就是程序员用代码设计出来的任务切换机制
注意2:
协程一定是发生在线程里的
协程并不是在线程之间切换
而是线程内部多个任务在做切换
本质就是一个线程里,写了很多任务,由事件循环统一调度
注意3:
当任务遇到IO操作时:任务会被挂起
当IO操作完成之后,任务会恢复执行
注意4:
协程依赖(事件循环)
注意5:
协程的目标就是尽可能减少线程之间的切换
协程函数:(coroutine Function)使用[async]关键字修饰的函数,就是协程函数
协程对象:(coroutine Object)调用协程对象就会得到协程对象
注意:调用协程函数,并不会执行协程函数的代码
协程对象只能调用一次之后自动销毁
import asyncio
async def work():
print(f'开始工作')
print(f'正在工作')
print(f'工作结束')
return f'结束'
#通过协程函数调用得到协程对象
coroutine_obj = work()
print(coroutine_obj)
#将协程对象交给asyncio.run(),asyncio.run()会把协程对象包装成一个任务交给事件循环来执行
res = asyncio.run(coroutine_obj)
print(res)
await:
1:挂起:await会暂停当前的协程执行
2:等待:遇到await关键字,事件循环会立刻安排await之后的对象去执行并且等到该对象执行完毕
第一种情况:如果等待对象中的代码没有包含IO,此时事件循环是拿不到CPU控制权的,无法调度循环中的其他事务,不会发生任务切换
第二种情况:如果等待对象中包含IO,那么CPU的控制权就交给了事件循环,事件循环会安排执行其他任务(有的情况下)
3:恢复当await后的对象执行完毕之后,事件循环会立刻恢复之间被挂起的协程,该协程会从当前挂起的位置继续执行,并拿到返回值
await之后只能写可等待对象,协程对象,Future对象,Task对象
事件循环将任务交给CPU执行,如果看到了wait关键字就会把任务挂起,从而执行后续代码
事件循环是拿不到CPU控制权的,无法调度循环中的其他事物,不会发生任务切换
import asyncio
import time
async def work(n,delay):
print(f'{n}开始工作')
print(f'{n}正在工作')
await asyncio.sleep(delay)
print(f'{n}工作结束')
return f'{n}结束'
async def main():
print('main开始工作')
start = time.time()
res1 = await asyncio.gather(work(1,2),work(2,2),work(3,3))
print(res1)
print('main结束',time.time()-start)
return 'main结束'
res = asyncio.run(main())
print(res)
import asyncio
import time
async def work(n,delay):
print(f'{n}开始工作')
print(f'{n}正在工作')
await asyncio.sleep(delay)
print(f'{n}工作结束')
return f'{n}结束'
async def main():
print('main开始工作')
start = time.time()
res1 = await work(1,2)
print(res1)
res2 = await work(2, 2)
print(res2)
res3 = await work(3, 2)
print(res3)
print('main结束',time.time()-start)
return 'main结束'
res = asyncio.run(main())
print(res)
传统图片下载
图片是一张一张下载的,当图片没有下载完成,后一张图片就不能开始下载,就属于典型的同步下载
import requests
def download(url):
print()
response = requests.get(url)
with open(url[-10:],'wb') as file:
file.write(response.content)
print('')
def main():
url_list = [
]
for url in url_list:
download(url)
main()
协程图片下载
asyncio.gather
import aiohttp
import asyncio
async def download(session,url):
print()
response = await session.get(url)
content = await response.read()
with open(url[-11:],'wb') as file:
file.write(response.content)
print('')
await response.release()
async def main():
url_list = [
"https://puui.qpic.cn/vpic_cover/l351257a0h4/l351257a0h4_1683069032_vt.jpg/720"
]
session = aiohttp.ClientSession()
coroutine_list = [download(session,url) for url in url_list]
await asyncio.gather(*coroutine_list)
await session.close()
asyncio.run(main())
asyncio.run()
1:创建了一个事件循环
2:将收到的协程对象,包装成一个任务,交给事件循环
3:启动事件循环