C# async / await 用法

news/2024/4/29 3:19:15/文章来源:https://blog.csdn.net/qq_38693757/article/details/127867464

目录

一、简介

二、异步等待返回结果

三、异步方法返回类型

四、await foreach

五、Task.Delay

结束


一、简介

await 运算符暂停对其所属的 async 方法的求值,直到其操作数表示的异步操作完成。 异步操作完成后,await 运算符将返回操作的结果(如果有)。 当 await 运算符应用到表示已完成操作的操作数时,它将立即返回操作的结果,而不会暂停其所属的方法。 await 运算符不会阻止计算异步方法的线程。 当 await 运算符暂停其所属的异步方法时,控件将返回到方法的调用方。

二、异步等待返回结果

下面就演示 await 运算符常用的一些用法。

新建一个基于 .Net6 的 Winform 项目,界面就两个按钮,如下:

代码 

namespace 异步编程
{public partial class Form1 : Form{public Form1(){InitializeComponent();}private void button1_Click(object sender, EventArgs e){IsTrue = false;AwaitEnd();}private void button2_Click(object sender, EventArgs e){IsTrue = true;}private bool IsTrue = false; private Task<string> StartTimer(){var t = Task.Run(() =>{while (true){if (IsTrue)return "555";Thread.Sleep(100);}});return t;}private async void AwaitEnd(){Console.WriteLine("开始执行,时间:" + DateTime.Now.ToString());var res = await StartTimer();Console.WriteLine("结束:" + res + " 时间:" + DateTime.Now.ToString());}}
}

点击按钮1开始启动异步,点击按钮2,就返回结果,如果不点击按钮2,那么 while 循环就不会停止。

效果:

可以看到,点击了按钮1后,并不会让主线程卡死,窗体还是可以随意的拖动的,直到 StartTimer 方法将返回值返回回来后,才会继续执行后续的代码,这对一些需要阻塞线程,并获取另外的计算结果,然后才能继续计算的需求而言,有极大的帮助,比如读取数据库数据,如果网速比较慢,并且不会立刻就返回结果,用 await 运算符就可以在同一个方法里,等到获取到数据库返回结果后,再进行下一步运算,而不是从上到下,一下子就执行完了。

下面是以前我查询数据库写的代码,效果和上面演示中的 await 运算符是一样的,在下面的方法中,使用 Action 回调,代码都没写到一起,虽然逻辑一样,但用起来就不是那么的方便。

/// <summary>
/// 执行SQL语句,并获取值
/// </summary>
/// <param name="sql"></param>
/// <param name="callBack"></param>
private static void ExecuteAndReturnValue(string sql, Action<DataTable?> callBack)
{Func<DataTable?> Funcs = () =>{DataSet dataSet = MySqlHelper.GetDataSet(sql);if (dataSet == null || dataSet.Tables.Count == 0)return null;return dataSet.Tables[0];};//执行任务Task<DataTable?> printRes = Task.Run(Funcs);//等待任务完成printRes.GetAwaiter().OnCompleted(() =>{if (callBack != null)callBack(printRes.Result);});
}

当前的示例,只是执行单个任务,如果有多个任务,用下面的方法也是可以的,

private Task DoSomethingAsync(int x)
{return Task.Run(() =>{Thread.Sleep(1000);Console.WriteLine("值:" + x);});
}public async Task RunAsync()
{foreach (var x in new[] { 1, 2, 3 }){await DoSomethingAsync(x);}
}

DoSomethingAsync 方法中,返回值可以从另一个数组中获取到 Task 并执行,我这里就不写那么仔细了,如果用面向过程的写法,就是这么写的:


private async void Test()
{await Task.Run(async () =>{await Task.Delay(4000);Trace.WriteLine("第1个线程执行");});await Task.Run(async () =>{await Task.Delay(3000);Trace.WriteLine("第2个线程执行");});await Task.Run(async () =>{await Task.Delay(2000);Trace.WriteLine("第3个线程执行");});
}

三、异步方法返回类型

在方法里加上了 async 关键字后,返回值就只能使用固定的几个了,不然会报错。

异步函数的返回类型只能为: void、Task、Task<TResult>、ValueTask 或 ValueTask<TResult>

Task<TResult>: 代表一个返回值T类型的操作。

Task: 代表一个无返回值的操作。

void: 为了和传统的事件处理程序兼容而设计。

四、await foreach

可以使用 await foreach 语句来使用异步数据流,即实现 IAsyncEnumerable<T> 接口的集合类型。 异步检索下一个元素时,可能会挂起循环的每次迭代。

代码

private async void Test()
{IAsyncEnumerable<int> pullBasedAsyncSequence = ProduceAsyncSumSeqeunc(5);//开始另一项任务;用于使用异步数据序列!var consumingTask = Task.Run(() => ConsumeAsyncSumSeqeunc(pullBasedAsyncSequence));await Task.Delay(TimeSpan.FromSeconds(3));Console.WriteLine("搞一些其他事");//只是为了演示!等待任务完成!await consumingTask;Console.WriteLine("异步流演示完成!" );
}private async Task ConsumeAsyncSumSeqeunc(IAsyncEnumerable<int> sequence)
{Console.WriteLine("执行 ConsumeAsyncSumSeqeunc 方法");await foreach (var value in sequence){Console.WriteLine($"value: {value}");await Task.Delay(TimeSpan.FromSeconds(1));};
}private async IAsyncEnumerable<int> ProduceAsyncSumSeqeunc(int count)
{Console.WriteLine("执行 ProduceAsyncSumSeqeunc 方法");int index = 0;for (int i = 0; i < count; i++){await Task.Delay(TimeSpan.FromSeconds(0.5));yield return index += count;}
}

调用 Test 方法后,即可打印

五、Task.Delay

解释:创建将在时间延迟后完成的任务。命名空间: System.Threading.Tasks

在上面的演示中用到了多次,例:

await Task.Delay(TimeSpan.FromSeconds(0.5));

在 Delay 方法中,可以用 TimeSpan 中的时、分、秒 表示

参考:

Delay(Int32)

创建一个在指定的毫秒数后完成的任务。

Delay(TimeSpan)

创建一个在指定的时间间隔后完成的任务。

Delay(Int32, CancellationToken)

创建一个在指定的毫秒数后完成的可取消任务。

Delay(TimeSpan, CancellationToken)

创建一个在指定的时间间隔后完成的可取消任务。

结束

如果这个帖子对你有所帮助,欢迎 关注 、点赞 、留言

end

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

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

相关文章

使用STM32CubeMX实现按下按键,电平反转

需提前学习&#xff1a;使用STM32CubeMX实现LED闪烁 目录 原理图分析 按键部分原理图分析 LED部分原理图分析 STM32CubeMX配置 关于STM32CubeMXSYS的Debug忘记配置Serial Wire处理办法 GPIO配置 LED的GPIO配置 KEY1配置 关于PA0后面这个WKUP是什么&#xff1f; 那么啥…

利用ogg微服务版将oracle同步到kafka

ogg微服务版可以再界面上配置抽取、复制进程&#xff0c;不必进入到shell中进行配置&#xff0c;并且图形化界面可以看到更多信息。 系统架构 源端安装ogg for oracle 19C , 目标端安装ogg for bigdata 21C kafka 2.2 数据库&#xff1a;19C 所有软件安装在同台服务器上&#…

理解Linux32位机器下虚拟地址到物理地址的转化

文章目录前言一、基本概念介绍二、虚拟地址到物理地址的转化过程总结前言 简要介绍LINUX32位系统下虚拟地址到物理地址的转化过程。 一、基本概念介绍 在32位机器下&#xff0c;IO的基本单位是块&#xff08;块&#xff1a;4kb),在程序编译成可执行程序时也划分好了以4kb为单…

JVM【类加载与GC垃圾回收机制】

JVM【类加载与GC垃圾回收机制】&#x1f34e;一.JVM&#x1f352;1.1JVM简介&#x1f352;1.2JVM执行流程&#x1f34e;二.JVM运行时数据区&#x1f352;2.1 程序计数器(线程私有)&#x1f352;2.2 栈(线程私有)&#x1f352;2.3 堆(线程共享)&#x1f352;2.4 方法区(线程共享…

OWASP API SECURITY TOP 10

目录 1. API 安全风险 2. 细说TOP10 1. Broken Object Level Authorization 2. Broken User Authentication 3 Excessive Data Exposure 4 Lack of Resources & Rate Limiting 5 Broken Function Level Authorization 6 Mass Assignment 7 security misconfigura…

【原创】使用Golang的电商搜索技术架构实现

作者&#xff1a;黑夜路人 时间&#xff1a;2022年11月 一、背景&#xff1a; 现在搜索技术已经是非常主流的应用技术&#xff0c;各种优秀的索引开源软件已经很普遍了&#xff0c;比如 Lucene/Solr/Elasticsearch 等等主流搜索索引开源软件&#xff0c;让我们搭建一个优秀的…

【FLASH存储器系列十】Nand Flash芯片使用指导之一

目录 1.1 芯片简介 1.2 功能框图 1.3 存储结构 1.4 信号定义 1.5 双平面&#xff08;plane&#xff09;操作 1.6 Die间交错操作 1.7 错误管理 今天以MT29F8G08AJADAWP芯片为例&#xff0c;说明nand flash的操作方法。 1.1 芯片简介 这是一款镁光的容量8Gb&#xff0c;总…

liunx集成jmeter进行压测实践

首先liunx环境需要部署jdk 1,获取jmeter免安装包&#xff1a;点击我获取免安装包 2,获取jmeter-manger工具&#xff0c;用于生成报告&#xff0c;日志等 点击我获取工具 3,在服务器上新建一个文件夹存放jmeter&#xff0c;推荐在/usr/local/下面&#xff0c;我这里由于权限问…

E 排队(排列组合)[牛客小*白月赛61]

题面如下&#xff1a; 思路 or 题解&#xff1a; 对于一个长度为 nnn 的 排列组合 如果存在一对 逆序对 (x,y)(x, y)(x,y) xxx 在 yyy 的前面有 n∗(n−1)2\frac{n * (n - 1)}{2}2n∗(n−1)​ 种情况 剩下 n−2n - 2n−2 个位置可以随意填数进去&#xff0c;不会影响到逆序对 …

狗屎一样的面试官,你遇到过几个?

做了几年软件开发&#xff0c;我们都或多或少面试过别人&#xff0c;或者被别人面试过。大家最常吐槽的就是面试造火箭&#xff0c;进厂拧螺丝。今天就来吐槽一下那些奇葩&#xff08;gou&#xff09;一样的面试官 A 那是在我刚工作1年的时候&#xff0c;出去面试前端开发。 那…

Python编程 元组的创建

作者简介&#xff1a;一名在校计算机学生、每天分享Python的学习经验、和学习笔记。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​​ 目录 前言 一.元组知识点 二.元组(tuple) 1.元组介绍(掌握) 2.元组创建(掌握) 3.…

鉴源论坛 · 观模丨浅谈随机测试

作者 | 黄杉 华东师范大学软件工程学院博士 苏亭 华东师范大学软件工程学院教授 首发 | 鉴源论坛 观模 01 什么是随机测试 &#xff08;Random Testing&#xff09; 随机测试是一种使用随机、相互独立的程序输入来对计算机程序进行测试的黑盒软件测试&#xff08;在完全忽…

Springboot常用参数注解

访问路径为http://localhost:8080/ PathVariable GetMapping("/get/{id}/blank/{name}")public Map getValue(PathVariable("id") Integer id,PathVariable("name") String name,PathVariable Map<String,String> kv){Map map new Hash…

大一新生HTML期末作业 学生个人网页设计作业 HTML5响应式个人简历网站模板 web前端网页制作课作业

&#x1f389;精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业…

CNN (吴恩达 2021

week1-2 02_边缘检测例子_哔哩哔哩_bilibili ​ ​ 我们之前在说面部识别介绍过&#xff0c;要识别面部&#xff0c;都是从细微的边缘入手&#xff0c;一层一层聚类&#xff0c;最终实现人脸的识别。神经网络由浅层到深层&#xff0c;分别可以检测出图片的边缘特征 、局部特…

web前端大一实训 HTML+CSS+JavaScript王者荣耀(60页) web课程设计网页规划与设计 HTML期末大作业 HTML网页设计结课作业

&#x1f389;精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业…

【MySQL进阶】深入理解B+树索引底层原理

【MySQL进阶】深入理解B树索引底层原理 文章目录【MySQL进阶】深入理解B树索引底层原理一、前言——没有索引的查找1、在一个页中的查找2、在很多页中查找3、总结二、索引1、一个简单的索引方案2、InnoDB中的索引方案3、B 树4、聚簇索引5、二级索引6、回表7、联合索引三、InnoD…

【MySQL数据库笔记 - 进阶篇】(二)索引

✍个人博客&#xff1a;https://blog.csdn.net/Newin2020?spm1011.2415.3001.5343 &#x1f4da;专栏地址&#xff1a;暂定 &#x1f4dd;视频地址&#xff1a;黑马程序员 MySQL数据库入门到精通 &#x1f4e3;专栏定位&#xff1a;这个专栏我将会整理 B 站黑马程序员的 MySQL…

linux备份mysql8.0数据库脚本

文章目录环境要求步骤1、创建一个.sh文件编写shell脚本2、添加定时任务环境要求 linux系统&#xff0c;安装了mysql8.0 步骤 1、创建一个.sh文件编写shell脚本 创建文件的命令&#xff1a; vim ***.shshell文件文件参考自文章 链接 export LANGen_US.UTF-8 #注意&#xf…

Python如何爬取免费爬虫ip

做过大数据抓取的程序员应该都知道&#xff0c;正常市面上的爬虫ip只分为两种&#xff0c;一种是API提取式的&#xff0c;还有一种是账密形式隧道模式的。往往因为高昂费用而止步。对于初学者觉得没有必要&#xff0c;我们知道每个卖爬虫ip的网站有的提供了免费IP&#xff0c;可…