首页 > 其他分享 >30. 协程

30. 协程

时间:2024-10-04 22:23:38浏览次数:1  
标签:__ await 协程 函数 30 print asyncio

1.协程的概念

1.1 定义

进程是操作系统内部运行的程序

线程是进程内部运行的程序

协程是线程内部运行的程序

协程是单线程下的并发,又成微线程,英文名coroutine

1.2 协程的优点

 协程切换的开销更小

GIL锁导致同一时刻只能运行一个线程,一个线程内不会限制协程数,单线程就可以实现并发的效果,最大程度利用CPU

1.3 协程的缺点

协程的本质是单线程下的多任务处理,无法利用多核优势

如果协程发生阻塞,在没有使用异步I/O的情况下,那么整个线程将阻塞,所在线程的其它协程任务都不能运行

2. 协程的操作

2.1 协程函数

加上async关键字的函数就是协程函数

async def f1():
    ...

2.2 协程对象

协程函数调用后的返回值就是协程对象

async def f1():
    print(111)


res = f1()
print(res)

 按一般函数的调用方法调用协程函数不会报错,但是会发出警告

 按一般函数的调用方法调用协程函数,函数内部的代码不会执行,只是会返回一个协程对象。

2.3 asyncio模块

Python 3.4:asyncio 被正式引入标准库,是一个实现异步编程的模块。
Python 3.5:引入了 async 和 await 关键字,这使得协程的定义和使用更加直观和简洁。这些关键字取代了早期版本中的 @asyncio.coroutine 装饰器和 yield from 语法。

2.4 事件循环的概念

事件循环可以类比while循环来理解,在循环周期内运行一些任务,特定的条件下结束循环。

import asyncio

loop = asyncio.get_event_loop()

2.5 协程函数的两种调用方法,以解释器3.10版本为例

由协程对象的定义可知,按函数名( )无法调用协程函数,需要协程对象和事件循环配合才能实现

[1]方法一:

import asyncio

async def work():
    print(666)
    return 'work函数的返回值'

def create_coroutine():
    obj = work()  # 1.调用协程函数,生成协程对象
    circle = asyncio.get_event_loop()  # 2.建立一个事件循环
    circle.run_until_complete(obj)  # 3.将协程对象当作任务提交到事件循环的任务列表中,协程运行完成事件循环停止

if __name__ == '__main__':
    create_coroutine()

在 Python 3.10 中,这个警告是因为在没有活动事件循环的主线程中调用 asyncio.get_event_loop() 时,get_event_loop() 会自动创建一个新的事件循环,这种方式被认为是不推荐的。
为了避免这个警告,可以使用 asyncio.run() 来运行协程,这是从 Python 3.7 开始推荐的做法。asyncio.run() 会自动创建和关闭事件循环,简化了异步代码的编写。

 [2]方法二:

import asyncio

async def work():
    print(666)
    return 'work函数的返回值'

def create_coroutine():
    obj = work()  # 1.调用协程函数,生成协程对象
    asyncio.run(obj)  # 2.调用run函数启动协程对象

if __name__ == '__main__':
    create_coroutine()

方式二的本质和方式一是一样的,内部先建立事件循环,然后运行run_until_complete

需要注意的是,run函数在解释器3.7才加入

2.6 await关键字

await关键字用于等待一个async(异步)函数的结果,使用await可以让程序在等待某个操作完成的同时不阻塞整个事件循环,从而允许其它任务运行,对于I/O密集型的应用特别有用。

await关键字解决了一个协程阻塞而导致整个线程阻塞的问题。

注意事项:

1.使用await必须在async(异步)函数中,不能在非异步函数中使用。

2.await只能用于异步函数返回的协程对象。

3.在异步函数内部,await可以用来等待另一个异步函数的结果,这会暂停当前协程的运行,直到等待的协程完成,然后继续运行。

代码示例

import asyncio

async def f1():
    print('异步函数运行开始')
    await asyncio.sleep(1)  # 模拟异步操作,比如网络请求
    print('异步函数运行结束')
    return 666

async def f2():
    res = await f1()
    print(res)

asyncio.run(f2())  # 获取事件循环并运行f2()协程

分析:

f1是一个异步函数,使用了await来等待asyncio.sleep(1)。这实际上并不会让程序等待1秒,而是允许事件循环在这1秒内执行其它任务。

f2也是一个异步函数,等待f1的运行结果。

ascyncio.run(f2())启动事件循环并运行f2协程。

 2.7 Task对象

[1]概念

前面的协程代码都只创建了一个任务,即事件循环的列表中只有一个任务对象;如需在程序中创建多个任务对象,需要使用Task。

Task用于并发调度协程,通过asyncio.create(协程对象)的方式创建Task对象,可以让协程加入事件循环中等待被调度执行。

注意事项:

asyncio.create_task( )函数在python3.7中被加入,在之前的版本可以改用底层级的asyncio.ensure_future( )函数。

[2]创建多任务方式一

逐个创建任务

import asyncio

# 定义协程功能函数
async def work():
    print('协程运行开始')
    await asyncio.sleep(1)  # 模拟异步操作,比如网络请求
    print('协程运行结束')
    return 666

# 定义产生协程函数
async def create_coroutine():
    print('产生协程的函数运行开始')
    task1 = asyncio.create_task(work())  # 将work()得到的协程对象封装到Task对象中,并立即添加到事件循环的任务列表中,等待事件循环
    task2 = asyncio.create_task(work())  # 将work()得到的协程对象封装到Task对象中,并立即添加到事件循环的任务列表中,等待事件循环

    response1 = await task1  # 引用了await之后,task1遇到sleep不会阻塞整个线程
    response2 = await task2

    print(response1, response2)
    print('产生协程的函数运行结束')

if __name__ == '__main__':
    asyncio.run(create_coroutine())

 [3]创建多任务方式二

使用列表生成式生成任务

import asyncio

# 定义协程功能函数
async def work(num):
    print('协程运行开始')
    await asyncio.sleep(1)  # 模拟异步操作,比如网络请求
    print('协程运行结束')
    return num * num

# 定义产生协程函数
async def create_coroutine():
    print('产生协程的函数运行开始')
    # 将work()得到的协程对象封装到Task对象中,并立即添加到事件循环的任务列表中,等待事件循环
    task_list = [asyncio.create_task(work(i)) for i in range(1, 4)]

    # 引用了await之后,task1遇到sleep不会阻塞整个线程
    # 如果设置了timeout值,则意味着此处最多等待的秒,完成的协程返回值写入到done中,未完成则写到pending中
    # wait里面要放可迭代对象
    done, pending = await asyncio.wait(task_list, timeout=None)
    print(done)
    print(pending)
    print('产生协程的函数运行结束')

if __name__ == '__main__':
    asyncio.run(create_coroutine())

 [3]获取协程返回值

在步骤[2]的基础上使用async.gather()获取返回值

import asyncio

# 定义协程功能函数
async def work(num):
    print('协程运行开始')
    await asyncio.sleep(1)  # 模拟异步操作,比如网络请求
    print('协程运行结束')
    return num * 10

# 定义产生协程函数
async def create_coroutine():
    print('产生协程的函数运行开始')
    # 将work()得到的协程对象封装到Task对象中,并立即添加到事件循环的任务列表中,等待事件循环
    task_list = [asyncio.create_task(work(i)) for i in range(1, 4)]

    # 引用了await之后,task1遇到sleep不会阻塞整个线程
    # 如果设置了timeout值,则意味着此处最多等待的秒,完成的协程返回值写入到done中,未完成则写到pending中
    # wait里面要放可迭代对象
    done, pending = await asyncio.wait(task_list, timeout=None)
    response = await asyncio.gather(*task_list)
    print(response)
    print('产生协程的函数运行结束')

if __name__ == '__main__':
    asyncio.run(create_coroutine())

 需要注意的是,以上代码即使不运行 done, pending = await asyncio.wait(task_list, timeout=None),也能获取到返回值。

 

标签:__,await,协程,函数,30,print,asyncio
From: https://www.cnblogs.com/hbutmeng/p/18445346

相关文章

  • 2024初秋集训——提高组 #30
    B.硬币问题题目描述有\(N\)种硬币,每种都有无限个。求\([1,m]\)中有多少种面额是不能被凑出来的。思路我们可以先求出不使用\(w_1\)凑出来的数,由于之后可以再添加若干个\(w_1\)。所以对于\(\bmodw_1\)同余的数只需看较小的数。这明显就是一个最短路。对于每种余数求......
  • 测试H7-TOOL的CANFD助手J1939批量数据传输连续运行30个小时稳定不丢包
    根据客户需求做的一个不断电连续运行测试。测试条件1、H7-TOOL的CAN/CANFD助手控制一个节点设备2、使用J1939协议3、经典CAN方式,波特率250KbpsJ1939测试命令,250ms一次发送接收测试昨天下午三点到今晚9点半,共计30个小时不断电连续测试,实时记录的文件:现在还在持续运行的......
  • 2024/09/30 模拟赛总结
    \(0+0+42+40\),T1在写正解的时候突然比赛还有1分钟结束,然后把freopen注释的暴力在最后几秒交了上去#A.博弈唐氏xor-hashing,首先博弈游戏很简单,如果有一个数的出现次数是奇数则先手必胜,否则先手必败那么先手必败的条件就是路径上所有边权都是两两配对的,即异或和为\(0\)。那......
  • [20240930]关于共享池-表对象在库缓存探究2.txt
    [20240930]关于共享池-表对象在库缓存探究2.txt--//以前探究过sql语句在共享池存在父子游标,父游标存在堆0,子游标堆0,堆6,通过各种指针链接起来,--//父游标的堆0上保存了所有子游标的列表和各个子游标的句柄指针,子游标的堆6中保存了解析过的执行计划等解析信息。--//前几天测试表对象......
  • COMP3230 Principles of Operating Systems
    COMP3230PrinciplesofOperatingSystemsProgrammingAssignmentOneDuedate:Oct.17,2024,at23:59Total13points–ReleaseCandidateVersion2ProgrammingExercise–ImplementaLLMChatbotInterfaceObjectivesAnassessmenttaskrelatedto......
  • CSP2024-30
    A题意:将一个圆等分为\(K\)分,给出其中\(n\)个等分点的编号,\(x_i<x_{i+1}\)。有向边\(i\toj\)存在,当且仅当\(j\)是距离\(i\)最大的点(不唯一),且与图中其他边无交点(端点不算)。求图中最多有多少条边。\(3\leK\le10^9,3\len\le\min(K,10^5)\)。引理:不存在......
  • 跨过坦克300,捷途旅行者成市场新贵
    在坦克300稳坐燃油“方盒子”SUV王座的日子里,消费者们对于这款车型的热衷可谓是如痴如醉,纷纷选择预定,翘首以盼提车之日的到来。然而,市场的风云变幻莫测,捷途旅行者的横空出世,犹如一匹黑马,打破了原有的市场格局。捷途旅行者上市后,其强劲的市场表现让坦克300的市场份额受到了......
  • 华为 HCIP-Datacom H12-821 题库 (30)
    ......
  • C/C++算法编程笔记(2024.9.26-9.30)
    一、并查集学习一:1、寻找根节点(两种)intfind(intx){if(x!=city[x]) city[x]=find(city[x]);returncity[x];}intfind(intx){ returnfa[x]==x?x:fa[x]=find(fa[x]);}2、合并不同集合voidmerge(intx,inty){inta=find(x);intb......
  • 【办公类-48-03】20240930每月电子屏台账汇总成docx-3(三园区合并EXCLE,批量生成3份word
    背景需求:前期电子屏汇总是“总园”用“”问卷星”、“一分园”用“腾讯文档”,二分园“用“手写word””【办公类-48-02】20240407每月电子屏台账汇总成docx-2(腾讯文档xlsx导入docx,每页20条)【办公类-48-02】20240407每月电子屏台账汇总成docx-2(腾讯文档xlsx导入docx,每页20......