详细分析python中的 async 和 await(附Demo)

目录

  • 前言
  • 1. 基本知识
  • 2. Demo
    • 2.1 Demo1(同步)
    • 2.2 Demo2(错误)
    • 2.3 Demo3(不正确的异步)
    • 2.4 Demo4(正确异步)
  • 3. 完整版
  • 4. 拓展
    • 4.1 asyncio.create_task(coroutine)
    • 4.2 asyncio.gather(*coroutines_or_futures, return_exceptions=False)
    • 4.3 字符串拼接

前言

对于异步的基本知识推荐阅读我之前的文章:

  1. 详细讲解Python中的aioschedule定时任务操作
  2. java关于@Async异步调用详细解析附代码
  3. 【操作系统】线程与进程的深入剖析(全)
  4. 【操作系统】守护线程和守护进程的区别

1. 基本知识

在Python中,asyncawait是用于异步编程的关键字,引入了异步/协程(coroutine)的概念

异步编程是一种处理并发任务的方式,使得程序能够在等待某些I/O操作(如文件读写、网络请求等)的同时继续执行其他任务,而不会发生阻塞

  • 异步(Asynchronous):在异步编程中,程序不会等待某些I/O操作完成,而是继续执行其他任务,待操作完成后再回来处理结果
  • 协程(Coroutine):协程是一种轻量级的线程,可以在执行过程中暂停并让出控制权,然后在需要时恢复执行
    使用协程可以更有效地利用系统资源,避免线程切换的开销

作用:

  • 提高程序效率:异步编程可以充分利用I/O等待时间,使得程序在等待操作完成时能够继续执行其他任务,从而提高了整体程序的效率。
  • 改善用户体验:在网络编程中,异步操作可以避免阻塞用户界面,使得应用程序更加流畅。
  • 简化并发编程:通过使用async和await关键字,可以更方便地编写并发程序,避免了传统多线程编程中的锁和同步问题。

2. Demo

以下例子会一步步体现异步的重要性!

2.1 Demo1(同步)

为了比较异步,先给出同步的例子:

from time import sleepdef greet(name):print("Hello, " + name)sleep(2)  # 模拟一个耗时的操作print("Goodbye, " + name)# 运行主函数
if __name__ == "__main__":greet("码农")greet("研究僧")

执行的顺序如下:
(这就是同步,需要等待上一个操作执行完)

在这里插入图片描述

2.2 Demo2(错误)

为了引入异步,我们先使用这个代码进行演示:(以下为错误代码)

from time import sleepasync def greet(name):print("Hello, " + name)sleep(2)  # 模拟一个耗时的操作print("Goodbye, " + name)# 运行主函数
if __name__ == "__main__":greet("码农")greet("研究僧")

输出结果如下:

F:\python_project\test\main.py:19: RuntimeWarning: coroutine 'greet' was never awaitedgreet("码农")
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
F:\python_project\test\main.py:20: RuntimeWarning: coroutine 'greet' was never awaitedgreet("研究僧")
RuntimeWarning: Enable tracemalloc to get the object allocation traceback

截图如下:

在这里插入图片描述

通过实战完善知识点:

在Python中,asyncawait是一对配合使用的关键字,用于定义异步函数和在异步函数中等待其他异步操作完成

配合使用可以实现协程的特性,使得异步编程更加简洁和易于理解

  • async关键字:
    async用于定义一个异步函数,表明该函数是一个协程,可以在其中使用await关键字等待其他异步操作完成
    异步函数的执行不会阻塞事件循环,而是会立即返回一个协程对象。

  • await关键字:
    await用于在异步函数内部等待其他协程执行完成,后面通常跟着一个需要等待的协程对象
    当遇到await关键字时,事件循环会挂起当前的协程,并执行其他任务,直到等待的协程完成后才会恢复执行当前协程

这两个关键字配合使用的好处在于:

  • 简化异步编程:使用asyncawait关键字可以使异步编程更加直观和易于理解,避免了回调函数和复杂的异步调度逻辑。

  • 实现协程asyncawait的组合使得函数可以在执行过程中暂停并恢复,实现了协程的特性,可以更灵活地处理异步任务。

  • 提高可读性:使用asyncawait可以使异步代码更加清晰和可读,使得程序逻辑更易于理解和维护。

2.3 Demo3(不正确的异步)

修正为如下:(正确)

import asyncio
from time import sleep# 定义一个异步函数
async def greet(name):print("Hello, " + name)sleep(2)  # 模拟一个耗时的操作print("Goodbye, " + name)async def main():await greet("码农")await greet("研究僧")# 运行主函数
if __name__ == "__main__":asyncio.run(main())

或者

import asyncio# 定义一个异步函数
async def greet(name):print("Hello, " + name)await asyncio.sleep(2)  # 模拟一个耗时的操作print("Goodbye, " + name)async def main():await greet("码农")await greet("研究僧")# 运行主函数
if __name__ == "__main__":asyncio.run(main())

这两者的输出都为如下:

在这里插入图片描述

光看上面的代码也只是同步输出,而不是异步输出的结果

2.4 Demo4(正确异步)

为了体现异步执行的效果,可以使用asyncio.create_task()创建任务并发执行

import asyncio# 定义一个异步函数
async def greet(name):print("Hello, " + name)await asyncio.sleep(2)  # 使用异步的sleep函数print("Goodbye, " + name)# 执行异步函数
async def main():# 创建任务并发执行task1 = asyncio.create_task(greet("码农"))task2 = asyncio.create_task(greet("研究僧"))# 等待所有任务完成await asyncio.gather(task1, task2)# 运行主函数
if __name__ == "__main__":asyncio.run(main())

截图如下:

在这里插入图片描述

3. 完整版

完整版代码如下:

import asyncio
from datetime import datetime# 定义一个异步函数
async def greet(name):print("Hello, " + name + str(datetime.now()))await asyncio.sleep(2)  # 使用异步的sleep函数print("Goodbye, " + name + str(datetime.now()))# 执行异步函数
async def main():# 创建任务并发执行task1 = asyncio.create_task(greet("码农"))task2 = asyncio.create_task(greet("研究僧"))# 等待所有任务完成await asyncio.gather(task1, task2)if __name__ == "__main__":start = datetime.now()  # 记录程序开始执行的时间asyncio.run(main())  # 运行主函数end = datetime.now()  # 记录程序结束执行的时间print('elapsed time =', end - start)  # 输出执行时间

输出结果如下:

在这里插入图片描述

4. 拓展

对于上述代码,有个别函数拓展如下

asyncio.create_task()asyncio.gather() 是 Python 中 asyncio 模块中的两个重要函数,用于创建和管理协程任务。都用于在异步编程中管理多个协程的执行,但是有着不同的作用和用法。

总的来说,asyncio.create_task() 用于并发执行多个协程任务,而 asyncio.gather() 用于等待多个协程任务的全部完成,并且可以收集执行结果
这两个函数是 asyncio 中协程任务管理的重要工具

4.1 asyncio.create_task(coroutine)

  • asyncio.create_task() 用于创建一个协程任务,并安排其立即执行
    接受一个协程对象作为参数,并返回一个任务对象
    该任务对象可以用来控制和管理该协程的执行,包括取消、等待其执行完成等
import asyncioasync def my_coroutine():await asyncio.sleep(1)print("Coroutine executed")async def main():task = asyncio.create_task(my_coroutine())await task  # 等待任务执行完成asyncio.run(main())

以上 使用 asyncio.create_task() 可以方便地并发执行多个协程

4.2 asyncio.gather(*coroutines_or_futures, return_exceptions=False)

  • asyncio.gather() 用于同时运行多个协程,并等待全部完成
    接受一系列的协程对象(或者 Future 对象)作为参数,并返回一个协程对象,该协程对象会在所有给定的协程都执行完毕后完成
import asyncioasync def coro1():await asyncio.sleep(1)return "Coroutine 1"async def coro2():await asyncio.sleep(2)return "Coroutine 2"async def main():result = await asyncio.gather(coro1(), coro2())print(result)asyncio.run(main())

4.3 字符串拼接

对于输出函数来说,一般都由字符串组成
如果使用其他非字符串则需要进行转化

datetime.now()返回的是一个datetime对象,不能直接与字符串拼接
需要将datetime对象转换为字符串类型才能进行拼接

使用str()函数将datetime对象转换为字符串

print("Hello, " + name + ", 时间:" + str(datetime.now()))

或者使用字符串的format()方法进行格式化输出

print("Hello, {}, 时间: {}".format(name, datetime.now()))

或者使用 f-string 格式化字符串

print(f"Hello, {name}, 时间: {datetime.now()}")

这些都是将datetime.now()的结果转换为字符串后再与其他字符串进行拼接的方法

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/459739.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PAT-Apat甲级题1009(python和c++实现)

PTA | 1009 Product of Polynomials 1009 Product of Polynomials 作者 CHEN, Yue 单位 浙江大学 This time, you are supposed to find AB where A and B are two polynomials. Input Specification: Each input file contains one test case. Each case occupies 2 lin…

【社交电商】带直播电商功能,可以DIY前端,可以H5和小程序一般商城常用功能齐全

第一次接触这个系统,感觉和微擎有点像。也是一个主体,也很多插件的那种。 测试了下。安装成功了,站长亲测没有问题,一切都挺完善的,不过系统比较庞大,可能新手熟悉起来要一定的过程。 站长整理了一份简要…

3060ti显卡+cuda12.1+win10编译安装生成fastdeploy的c++与python库

在cuda12中,调用官方发布的fastdeploy会出现报错,故此自行编译fastdeploy库。 官网编译教程:https://github.com/PaddlePaddle/FastDeploy/blob/develop/docs/cn/build_and_install/gpu.md 可选编译选项 编译选项 无论是在何平台编译,编译时仅根据需求修改如下选项,勿…

使用pygame生成红包封面

import pygame import sys# 初始化pygame pygame.init()# 设置红包封面尺寸 size width, height 640, 960 screen_color (255, 0, 0) # 红色背景# 创建窗口 screen pygame.display.set_mode(size) pygame.display.set_caption(红包封面)# 加载龙形图片 dragon_image pygam…

CDH6.3.2 多 Spark 版本共存

一 部署Spark客户端 1.1 部署spark3客户端 tar -zxvf spark-3.3.1-bin-3.0.0-cdh6.3.2.tgz -C /opt/cloudera/parcels/CDH/lib cd /opt/cloudera/parcels/CDH/lib mv spark-3.3.1-bin-3.0.0-cdh6.3.2/ spark3将 CDH 集群的 spark-env.sh 复制到 /opt/cloudera/parcels/CDH/li…

AcWing 1238 日志统计(双指针算法)

题目概述 小明维护着一个程序员论坛。现在他收集了一份”点赞”日志,日志共有 N 行。 其中每一行的格式是: ts id表示在 ts 时刻编号 id 的帖子收到一个”赞”。 现在小明想统计有哪些帖子曾经是”热帖”。 如果一个帖子曾在任意一个长度为 D 的时间段…

Unity2D 学习笔记 0.Unity需要记住的常用知识

Unity2D 学习笔记 0.Unity需要记住的常用知识 前言调整Project SettingTilemap相关(创建地图块)C#脚本相关程序运行函数private void Awake()void Start()void Update() Collider2D碰撞检测private void OnTriggerStay2D(Collider2D player)private void…

Sublime Text 3配置 Node.js 开发环境

《开发工具系列》 Sublime Text 3配置 Node.js 开发环境 一、引言二、主要内容2.1 初识 Sublime Text 32.2 初识 Node.js2.3 接入 Node.js2.3.1 下载并安装 Node.js2.3.2 环境变量配置 2.4 配置 Node.js 开发环境2.5 编写 Node.js 代码2.6 运行 Node.js 代码 三、总结 一、引言…

大数据术语系列(1)——COW和MOR,我如何使用chatgpt通俗易懂地理解了hudi这两种表类型

从传统数据库到大数据的转变,首当其冲的是各种术语的理解。 所以我与chatgpt发生了一系列对话,以便于我能快速理解这些术语。 我先把汇总的结果放在前边,后边会一步步地来说明我是如何获取这些信息的。前边我也发过一些关于chatgpt提示词相…

基于hadoop+spark的大规模日志的一种处理方案

概述: CDN服务平台上有为客户提供访问日志下载的功能,主要是为了满足在给CDN客户提供服务的过程中,要对所有的记录访问日志,按照客户定制的格式化需求以小时为粒度(或者其他任意时间粒度)进行排序、压缩、打包,供客户进行下载,以便进行后续的核对和分析的诉求。而且CDN…

Vulnhub靶机:hacksudoLPE

一、介绍 运行环境:Virtualbox 攻击机:kali(10.0.2.15) 靶机:hacksudoLPE(10.0.2.47) 目标:获取靶机root权限和flag,该靶机是一个练习提权的靶场,主要以提…

【Linux】POSIX信号量基于环形队列的生产消费模型

需要云服务器等云产品来学习Linux的同学可以移步/–>腾讯云<–/官网&#xff0c;轻量型云服务器低至112元/年&#xff0c;优惠多多。&#xff08;联系我有折扣哦&#xff09; 文章目录 引入1. POSIX信号量1.1 信号量的概念1.2 信号量的使用1.2.1 信号量的初始化1.2.2信号…