慢就是快16-1协程

第一种描述:协程是一种可以被挂起,并且在挂起之后,还可以恢复执行的函数。

第二种描述:协程又称微线程,是一种用户态内的上下文切换技术。

协程对象

1.协程函数(coroutineFunction):使用『async关键字』修饰的函数,就是协程函数。

2.协程对象(coroutine Object):调用[协程函数』,就会得到[协程对象』。

注意:调用『协程函数』,并不会执行『协程函数』中的代码。

python 复制代码
import asyncio
# 定义一个协程函数
async def work():
    print('work开始')
    print('working')
    print('work结束')
    return '工作结束'

# 调用协程函数,会得到协程对象
coroutine_obj=work()

# asyncio.run方法做了3件事:
# 1.创建一个事件循环。
# 2.将收到的协程对象,包装成一个任务(task),交给事件循环。
# 3.启动事件循环。
#   注意:asyncio.run会阻塞当前线程,直到任务执行完毕,并返回该任务return的最终结果。
res=asyncio.run(coroutine_obj)
print(res)

await关键字

  1. 挂起:await会暂停当前协程的执行。

2.等待:遇到await关键字,事件循环会立即安排await后面的对象去执行,并等待该对象执行完成,并且可以拿到执行结果。

关键点:在执行await后面的对象时,会出现两种情况:

情况一:如果在执行该对象中的代码时,遇到了【awaitI/0操作】(需要等待外部资源返回结果的操作)

例如:网络请求、文件读写等。

那CPu的控制权就会交给事件循环。

事件循环会去调度循环中的其他任务(如果有的话)

python 复制代码
import asyncio
async def work():
    print('work开始')
    print('working')
    await asyncio.sleep(2)
    print('work结束')
    return '工作结束'

async def main():
    print('main开始')
    res=await work()
    print(res)
    print('main_ing')
    print('main结束')
    return 'main结束'

# 调用协程函数,会得到协程对象
coroutine_obj=main()
res=asyncio.run(coroutine_obj)
print(res)

情况二:如果该对象中的代码,不包含任何【awaitI/0操作】

例如:print打印、数学计算、逻辑计算等.

此时事件循环拿不到cPu控制权,无法调度循环中的其他任务,不会发生任务切换。

python 复制代码
​import asyncio
async def work():
    print('work开始')
    print('working')
    print('work结束')
    return '工作结束'

async def main():
    print('main开始')
    await work()
    print('main_ing')
    print('main结束')
    return 'main结束'

# 调用协程函数,会得到协程对象
coroutine_obj=main()
res=asyncio.run(coroutine_obj)
print(res)

3.恢复:当await后的对象执行完毕,事件循环会恢复之前被挂起的协程,该协程会从当时挂起的位置继续执行,并拿到返回值

注意点:

await后面只能写『可等待的对象』,常见的可等待对象:1.协程对象、2.Future对象、3.Task对象

多个任务_同步执行

python 复制代码
import asyncio
async def work(n,delay):
    print(f'work{n}开始')
    print(f'{n}working')
    await asyncio.sleep(delay)
    print(f'work{n}结束')
    return f'{n}工作结束'

async def main():
    print('main开始')
    # 调用三次work函数,分别得到三个协程对象
    coroutine1= work(1,2)
    coroutine2= work(2,2)
    coroutine3= work(3,2)
    # 此处会等待coroutine1执行完成
    res1=await coroutine1
    print(res1)
    # coroutine1完成后,再等待coroutine2完成
    res2=await coroutine2
    print(res2)
    # coroutine2完成后,再等待coroutine3完成
    res3=await coroutine3
    print(res3)
    print('main结束')
    return 'main的返回值'

# 将协程对象交给事件循环
res=asyncio.run(main())
print(res)

多个任务_异步执行

python 复制代码
import asyncio
import time
async def work(n,delay):
    print(f'work{n}开始')
    print(f'{n}working')
    await asyncio.sleep(delay)
    print(f'work{n}结束')
    return f'{n}工作结束'

async def main():
    print('main开始')
    start=time.time()
    # asyncio.create_task 会把一个协程对象包装成一个可被事件循环调度的任务,并注册到事件循环中
    # 简写
    res=await asyncio.gather(work(1,2),work(2,2),work(3,2))
    print(res)
    # task1= asyncio.create_task(work(1,2))
    # task2= asyncio.create_task(work(2,2))
    # task3= asyncio.create_task(work(3,2))
    # 此处会等待task1执行完成
    # res1=await task1
    # print(res1)
    # task1完成后,再等待task2完成
    # res2=await task2
    # print(res2)
    # task2完成后,再等待task3完成
    # res3=await task3
    # print(res3)
    print('main结束',time.time()-start)
    return 'main的返回值'

# 将协程对象交给事件循环
res=asyncio.run(main())
print(res)

案例-下载图片

python 复制代码
import requests
import aiohttp
import asyncio

# 协程
async def download_picture(session,url):
    print(f'开始下载:{ur1}')
    # 发送网络请求,获取图片,等待的过程是IO等待
    res=await session.get(url)
    # 等待数据
    cont=await res.read()
    with open(url[-10:],'wb') as file:
        file.write(cont)

    # 释放连接资源
    await res.release()
    print('下载并保存完毕')

async def main():
    url_list = [
        "",
        "",
        ""
    ]
    # 创建会话对象(发送请求的工具)
    session=aiohttp.ClientSession()
    coroutine_list=[download_picture(session,url) for url in url_list]
    await asyncio.gather(*coroutine_list)
    # 关闭会话
    await session.close()

asyncio.run(main())

# 传统
# def download_picture(url):
#     print(f'开始下载:{ur1}')
#     #发送网络请求,获取这张图片
#     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_picture(url)

# main()
相关推荐
Oiiouui15 分钟前
linux服务器部署Logto后端与对应前端的实现
linux·服务器·前端·后端
前端小D30 分钟前
JS核心底层
前端·javascript
律宏阔41 分钟前
Taro 4 项目从 npm 迁移到 pnpm 踩坑实录
前端·微信小程序·taro
用户308169987648541 分钟前
同一句话问 AI 15 次,答案 15 个:temperature 0 实测也不稳
前端
SameX44 分钟前
ArkTS 做 5 态数据流 —— 咖啡电量的代谢状态机怎么驱动 UI
前端
5233AI开发笔记1 小时前
API 返回 429:先区分限速、并发和配额,再决定是否重试
python
Dovis(誓平步青云)1 小时前
启元 T1 Pro 人机相声搭档:语音-触摸双通道的启元机器人节奏引擎设计
开发语言·前端·javascript·microsoft·交互
databook1 小时前
经常听到的透视表是干什么的?
python·数据分析·pandas
爱吃烧烤的技术渣1 小时前
别再手写 CRUD 了:我把 Element Plus 的工作量压缩成一份列 schema
前端·vue.js