关于c#中异步async和await的理解
之前给大家介绍了所谓异步编程的用法,但是没有细致的理解到,今天想和大家一起探讨一下;
前文:
C#笔记14 异步编程Async,await,task类-CSDN博客
异步的起初
应用程序会启动一个进程,一个进程可以有很多线程。
如果一个线程,我们给他命名为主线程。
这个线程如果一直往下走,只有一条线,这就是单线程。
还是这个线程,如果它运行的途中创建了新的小伙伴去执行其他任务,这就是多线程。
现在我们的主线程正在做着自己的事情类似于展示一个界面之类的,此时创建一个线程去后台执行其他任务,主线程不去管它,这就是异步。
所以多线程的起初就是异步的。
同步的出现
现在,主线程创建了两个小弟,两个小弟功能差不多,这两个小弟为了抢占一个资源,打起来了。这可不行对吧,于是我们就设立各种同步机制和同步锁,控制他们学会等待。
等待的方式各不相同,但是毫无疑问,线程间互相有了约束和阻塞。
到这里其实我们想做的事情已经基本完成了。
线程各司其职遇到资源就进行同步机制的等待和唤醒操作。
但是还是会有问题,比如多线程的管理,小弟太多了,根本管不过来,小弟之间使用资源的调度原则不够公平等等。当然了,这要求程序员的管理和操作系统的调度配合。
除此之外也发现管理多线程的方式不够先进:
管理的困难
主线程是老大,今天派小弟出去办事,小弟办事之后,确实办完了,但是主线程不知道小弟已经办完了,这时候是不是有小伙伴要想到C#中的委托和事件了?
这样就可以让小弟通知老大哥自己做好了,老大哥订阅了小弟的这个事件,这样就能在小弟完成事件的时候执行对应的方法了。
但是每一个小弟都这样,老大哥要手动管理这些事件,就好像老大哥每天都得坐在办公室听汇报了一样,尤其是管理线程的我们觉得很烦,这个组织太杂乱了!
尤其是什么情况?需要反复派出小弟去干活的时候,比如密集的io环境,我们还要和每个小老弟都约定一个事件,啥时候通知老大哥。
尤其是线程一多,老大哥虽然不迷糊但是老大哥也很烦,但是我们程序员,也就是负责真正管理小弟的人迷糊了。这可怎么办?
此时:
如果不派小弟去干,自己干,老大哥自己的事情就做不好了。(阻塞)
如果派出小弟,让小弟自己干自己的,老大又不知道到底干的什么情况了,就算小弟已经把结果搞出来了,已经通过什么形式提交了也不知道。(多线程异步)
如果手动告诉小弟怎么通知老大,这下倒是可以了,但是咱们秘书(程序员)可怜了,天天就负责管理每个小弟,告诉小弟在哪告诉老大,然后记下老大小弟给的数据怎么处理,用什么方法处理。(事件通知的多线程)
到这我们秘书就想到一个方法减轻自己的工作量。将社团改组,大哥和小弟都不是按所谓线程来做事了,而是新的机制或者说不同的任务处理者Task。
新的处理异步的方法
async和await出场!
async:用于标记一个方法是异步的,告诉编译器这个方法会有异步操作。该方法仍然可以在线程池中调度执行任务,但这个并不由 async 本身控制。
await:用于等待异步操作完成,而不会阻塞当前线程。它只会让出控制权,让当前线程去做其他事情,当操作完成时,再继续执行后续代码。
async标记一个事情,告诉老大和小弟,这个事情是异步的,这个事情要让小弟去干,不能影响老大哥工作。所以这个方法使用之后会立刻返回一个任务的引用作为结果,等到事情办完了这个结果才会被填充为指定的值。
await专门用来调用一个需要耗时间的操作,调用之后会让出控制权,等到再次获取控制权也就是后面等待的操作有结果的时候,如果异步方法有返回值的话,await还会自动把值从结果里拿出来给指定的对象。
老大哥调用异步方法就像派出一个小弟,task作为方法的返回值就像小弟给大哥留的纸条,等到小弟任务完成了,这个纸条上就会出现结果。这中间呢纸条就放在这里,。
await是逻辑上的等待这个结果,如果这个结果没有出现,后面的逻辑就不会执行。
意思是老大虽然后面有些事要等待这个事情,不代表老大就抛下自己手上的事情了,实际上老大还是在干活的。
你会发现小弟中间也会有一些await操作。
老大哥一调用这个事情啊,可以使用task,意思就是老大哥派出了这个小弟,但是自己没有去干奥,这个小东西就是小弟留给老大的小纸条,
await就是小弟告诉老大:“好,现在该到这里了,我得等某个任务完成了才能继续。
意思是什么?小弟办事也不是说立刻就办完了。也就是我们的方法内部也许还有耗时间的更具体的操作,比如老大让小弟读写一批文件,小弟可能要一个个文件读写,这就是小弟给老大的纸条。
await 就像说:“等这个任务做完了,再通知我,我再继续往下走。”
所以,await 的作用是让程序在某个任务完成之前,不阻塞其他操作。它并不会傻傻等着,而是会继续处理其他的事情,等到这个耗时操作完成后,再回到你指定的位置继续执行。
using System;
using System.Net.Http;
using System.Threading.Tasks;class Program
{static async Task Main(string[] args){Console.WriteLine($"{DateTime.Now:HH:mm:ss} - 大哥:开始做事,我让小弟去下载文件");// 大哥派小弟去干下载文件的活Task downloadTask = 小弟去下载文件Async("http://example.com/largefile");// 大哥自己继续干活for (int i = 0; i < 10; i++){Console.WriteLine($"{DateTime.Now:HH:mm:ss} - 大哥:我在忙别的事... {i}");await Task.Delay(1000); // 模拟大哥处理别的事情需要一些时间}// 等小弟把下载任务做完await downloadTask;Console.WriteLine($"{DateTime.Now:HH:mm:ss} - 大哥:小弟终于把文件下载完了,事情都做完了,收工!");}// 小弟去下载文件,过程可能很久static async Task 小弟去下载文件Async(string url){Console.WriteLine($"{DateTime.Now:HH:mm:ss} - 小弟:开始下载文件...");using (HttpClient client = new HttpClient()){// 模拟下载文件的耗时操作await Task.Delay(5000); // 假装下载需要5秒钟Console.WriteLine($"{DateTime.Now:HH:mm:ss} - 小弟:文件下载完了!");}}
}
10:00:00 - 大哥:开始做事,我让小弟去下载文件
10:00:00 - 小弟:开始下载文件...
10:00:00 - 大哥:我在忙别的事... 0
10:00:01 - 大哥:我在忙别的事... 1
10:00:02 - 大哥:我在忙别的事... 2
10:00:03 - 大哥:我在忙别的事... 3
10:00:04 - 大哥:我在忙别的事... 4
10:00:05 - 小弟:文件下载完了!
10:00:05 - 大哥:我在忙别的事... 5
10:00:06 - 大哥:我在忙别的事... 6
10:00:07 - 大哥:我在忙别的事... 7
10:00:08 - 大哥:我在忙别的事... 8
10:00:09 - 大哥:我在忙别的事... 9
10:00:09 - 大哥:小弟终于把文件下载完了,事情都做完了,收工!
可以看出来,大哥在派出小弟之后自己还在做事,事实上小弟此时也正在下载文件。(注意,这里的小弟不是某个特定的我们管理的线程,而是被我们的系统指派的线程池甚至就是操作系统在做。)
大哥的await就是等小弟。
小弟的await就是小弟等小弟。
注意,await不会让后面的代码提前执行,反而是会就像顺序执行一样来执行。
但是它这种等待和我们之前线程的等待又不太一样,因为这种等待是代码让出控制权给其他方法去执行。
异步方法之间的依赖
小弟之间也存在依赖的时候呢,就可以像下面一样了。
using System;
using System.Threading.Tasks;class Program
{static async Task Main(string[] args){Console.WriteLine($"{DateTime.Now:HH:mm:ss} - 老大哥:开始派小弟A去下载文件");// 小弟A开始下载文件,小弟B等他下载完Task 小弟A的任务 = 小弟A去下载文件Async();Task 小弟B的任务 = 小弟B等小弟A再处理文件Async(小弟A的任务);Console.WriteLine($"{DateTime.Now:HH:mm:ss} - 老大哥:我先干点其他的事...");// 等两个任务都完成await Task.WhenAll(小弟A的任务, 小弟B的任务);Console.WriteLine($"{DateTime.Now:HH:mm:ss} - 老大哥:小弟们都完成了,我收工!");}static async Task 小弟A去下载文件Async(){Console.WriteLine($"{DateTime.Now:HH:mm:ss} - 小弟A:开始下载文件...");await Task.Delay(3000); // 模拟耗时的下载过程Console.WriteLine($"{DateTime.Now:HH:mm:ss} - 小弟A:文件下载完了!");}static async Task 小弟B等小弟A再处理文件Async(Task 小弟A的任务){Console.WriteLine($"{DateTime.Now:HH:mm:ss} - 小弟B:我得等小弟A下载完才能干活...");await 小弟A的任务; // 等待小弟A的任务完成Console.WriteLine($"{DateTime.Now:HH:mm:ss} - 小弟B:现在小弟A下载完了,我开始处理文件...");await Task.Delay(2000); // 模拟文件处理时间Console.WriteLine($"{DateTime.Now:HH:mm:ss} - 小弟B:文件处理完了!");}
}
事实上,任务机制可以让我们像写同步代码一样来写一些需要异步的操作。
同样的代码逻辑,实际的执行上就会不同。
这和传统线程管理的方式不同,避免了管理线程和事件订阅以及那种嵌套回调函数的麻烦。
这只是当下我浅薄的理解,如果我说的有错,请帮我指出,感谢。
相关文章:
关于c#中异步async和await的理解
之前给大家介绍了所谓异步编程的用法,但是没有细致的理解到,今天想和大家一起探讨一下; 前文: C#笔记14 异步编程Async,await,task类-CSDN博客 异步的起初 应用程序会启动一个进程,一个进程可以有很多…...
mysql等保数据库命令
mysql数据库命令 默认安装位置:C:\Program Files\MySQL\MySQL Server 8.0\bin select version() from dual; desc mysql.user; 查看表中有哪些列 1、SELECT user, host, authentication_string, account_locked ,password_lifetime FROM mysql.user; 查询用户表…...

云平台在大规模设备管理和数据分析中的作用
在当代数字化转型的浪潮中,云平台作为信息技术基础设施的核心组件,扮演着无可替代的角色,尤其在大规模设备管理和数据分析领域,其重要性和影响力日益凸显。本文旨在深入探讨云平台如何通过其独特的优势,促进数据的高效…...

数据结构-树和二叉树
树 和 二叉树 1.树的概念 树 tree 是n(n>0)个节点的有限集 在任意的一个非空树中 (1)有且仅有一个特定的被称为 根(root) 的节点 (2)当n>1时, 其余的节点可分为m(m>0)个互不相交的有限集T1, T2, T3, .... …...

树和二叉树的概念以及结构
一起加油学数据结构 目录 树的概念以及结构 树的概念 树的相关概念 树的表示 二叉树的概念以及结构 二叉树的概念 特殊的二叉树 二叉树的性质 二叉树的存储结构 树的概念以及结构 树的概念 树是一种非线性的数据结构,它是由n(n>0)…...
c语言习题
第三章 数据类型、运算符与表达式 一 单项选择题 1.下面四个选项中,均不是 c 语言关键字的选项是( )。 A) define IF Type B) getc char printf C) include scanf case D…...

Python 低层多线程接口_thread的用法
_thread是python标准库中的一个低层多线程API,可以在进程中启动线程来处理任务,并且提供了简单的锁机制来控制共享资源的同步访问。本文就_thread模块的用法和特性做个简单的演示。 文章目录 一、进程和线程的区别二、_thread模块的用法2.1 派生线程2.2…...
flutter基础 --dart语法学习
由于想要写一款性能较好,但是又可以一套代码多个平台运行的客户端app,所以选择了flutter 就去看了官方文档,大体发现flutter使用的dart语言和java和js差不多,感觉就是缝合怪。 Dart 是一种面向对象的编程语言,语法上与 Java、JavaScript 等语言有一些相似之处&…...

新手必看:一步步教你绑定常见邮箱到第三方应用(如何绑定QQ、163、Hotmail、Gmail等邮箱)
文章目录 📖 介绍 📖🏡 演示环境 🏡📒 邮箱绑定 📒📫 QQ邮箱📫 163邮箱📫 Hotmail邮箱📫 Gmail邮箱📫 Yahoo邮箱📫 iCloud邮箱📫 其他邮箱⚓️ 相关链接 ⚓️📖 介绍 📖 你是否曾经为绑定第三方邮箱而感到困惑?你不是一个人!许多人在尝试将QQ邮…...
mac 怎么查看CPU核数
在 macOS 系统中,可以通过以下几种方法查看 CPU 核心数: 1. 使用“关于本机”查看 点击左上角的苹果图标()。选择“关于本机”。在弹出的窗口中,系统会显示 Mac 的基本信息,包括 CPU 的类型和核心数。比…...

Vue生命周期;Vue路由配置;vue网络请求;vue跨域处理
一,Vue生命周期 <template><div > <h1 click"changeText">{{ info }}</h1></div> </template><script> export default {name: HelloWorld,data(){return{info:"介绍组件生命周期"}},methods:{chang…...
汽车电子电气架构从12V提升至48V,带来那些好处? 包括那些改变?
标签: 汽车电子电气架构; 从12V提升至48V; 汽车电子电气架构从12V提升至48V,带来那些好处? 包括那些改变? 将传统汽车的电子电气架构电压从12V提升至48V,既有显著的优势,也需要对车…...

springboot实战学习笔记(2)
目录 1、手动创建springboot工程,选择Maven构建。 2、Maven生成的,可能需要再main目录下new一个resources目录,再在其下目录new一个配置文件。 3、 pom文件中让当前的工程继承父工程依赖:、删去无用依赖。 4、引入后端环境所需要的…...

Python练习宝典:Day 1 - 选择题 - 基础知识
目录 一、踏上Python之旅二、Python语言基础三、流程控制语句四、序列的应用 一、踏上Python之旅 1.想要输出 I Love Python,应该使用()函数。 A.printf() B.print() C.println() D.Print()2.Python安装成功的标志是在控制台(终端)输入python/python3后,命令提示符变为: A.&…...

macOS平台(intel)编译MAVSDK安卓平台SO库
1.下载MAVSDK: git clone https://github.com/mavlink/MAVSDK.git --recursive 2.编译liblzma 修改CMakeLists.txt文件增加C与CXX指令-fPIC set(CMAKE_C_FLAGS "-fPIC ${CMAKE_C_FLAGS}") set(CMAKE_CXX_FLAGS "-fPIC ${CMAKE_CXX_FLAGS}") 修改如下:…...
set的相关函数(3)
3.删除 //删除 /* int main() {set<int> s;s.insert({ 2,4,5,2,6,8,10,15 });for (auto e : s){cout << e << " ";}cout << endl;//删除最小的元素就删除排序后的首元素s.erase(s.begin());for (auto e : s){cout << e << "…...
Python MongoDB
MongoDB 是目前最流行的 NoSQL 数据库之一,使用的数据类型 BSON(类似 JSON)。 MongoDB 数据库安装与介绍可以查看我们的 MongoDB 教程。 PyMongo Python 要连接 MongoDB 需要 MongoDB 驱动,这里我们使用 PyMongo 驱动来连接。 …...

安国U盘量产工具系列下载地址
来源地址(访问需要科学工具):AlcorMP (Последняя версия ALCOR U2 MP v23.08.07.00.H) – [USBDev.ru] 版本列表: AlcorMP(最新版本的 ALCOR U2 MP v23.08.07.00.H) AlcorMP是在Alcor Mic…...

2024年最新版Vue3学习笔记
本篇文章是记录来自尚硅谷禹神2023年课程的学习笔记,不得不说禹神讲的是真的超级棒! 文章目录 创建Vue3工程main.ts文件解析初始化项目写一个简单的效果 Vue3核心语法setup函数setup和选项式的区别setup语法糖指定组件名称 响应式数据ref函数定义基本类…...

FX5 CPU模块和以太网模块的以太网通信功能
FX5 CPU模块和以太网模块的以太网通信功能的概要如下所示。 CPU模块的内置以太网端口的通信规格如下所示。 1、与MELSOFT的直接连接 不使用集线器,用1根以太网电缆直接连接以太网搭载模块与工程工具(GX Torks3)。无需设定IP地址,仅连接目标指定即可进行…...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...
CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型
CVPR 2025 | MIMO:支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题:MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者:Yanyuan Chen, Dexuan Xu, Yu Hu…...
ubuntu搭建nfs服务centos挂载访问
在Ubuntu上设置NFS服务器 在Ubuntu上,你可以使用apt包管理器来安装NFS服务器。打开终端并运行: sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享,例如/shared: sudo mkdir /shared sud…...

UE5 学习系列(三)创建和移动物体
这篇博客是该系列的第三篇,是在之前两篇博客的基础上展开,主要介绍如何在操作界面中创建和拖动物体,这篇博客跟随的视频链接如下: B 站视频:s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...

STM32F4基本定时器使用和原理详解
STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...
Golang dig框架与GraphQL的完美结合
将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用,可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器,能够帮助开发者更好地管理复杂的依赖关系,而 GraphQL 则是一种用于 API 的查询语言,能够提…...

MODBUS TCP转CANopen 技术赋能高效协同作业
在现代工业自动化领域,MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步,这两种通讯协议也正在被逐步融合,形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...

从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)
设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile,新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...

12.找到字符串中所有字母异位词
🧠 题目解析 题目描述: 给定两个字符串 s 和 p,找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义: 若两个字符串包含的字符种类和出现次数完全相同,顺序无所谓,则互为…...