C# async / await 用法
目录
一、简介
二、异步等待返回结果
三、异步方法返回类型
四、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
C# async / await 用法相关推荐
- javascript中的异步调用,promise对象,async/await用法
原生javascript中的的回调函数 即callback 就是通过回调函数来通知主程序 对于io 密集的非常好用:eg. file,DB读写,网络访问 异步: javascript就是个单线程语言, ...
- async/await用法详解
ES2017 标准引入了 async 函数,使得异步操作变得更加方便. async函数的定义方式 // 函数声明 async function fn() {}// 函数表达式 const fn = a ...
- 【面试Vue全家桶】vue前端交互模式-es7的语法结构?async/await
作者 | Jeskson 掘金 | https://juejin.im/user/5a16e1f3f265da43128096cb 2020.1.12 前端发请求,调用后端接口,来获取特定格式的数 ...
- async/await原来这就是语法糖
带大家基本了解了Promise内部的实现原理,而提到Promise,就不得不提一个东西,那就是async/await,async/await是一个很重要的语法糖,他的作用是用同步方式,执行异步操作.那 ...
- Promise async/await的理解和用法
Promise && async/await的理解和用法 为什么需要promise(承诺)这个东西 在之前我们处理异步函数都是用回调这个方法,回调嵌套的时候会发现 阅读性 和 调试 的 ...
- 浅谈async函数await用法
async和await相信大家应该不陌生,让异步处理变得更友好. 其实这玩意儿就是个Generator的语法糖,想深入学习得去看看Generator,不然你可能只停留在会用的阶段. 用法很简单,看代码 ...
- [译]JavaScript async / await:好处、坑和正确用法
原文地址:JavaScript async/await: The Good Part, Pitfalls and How to Use ES7通过介绍async/await使得JavaScript的异 ...
- promise用法_JavaScript中的async/await的用法和理解
昨天更新的是"JavaScript中的Promise使用详解",其实也就是说了下基本用法和自己对Promise的理解,可能有错误之处,也欢迎指出.今天就说一说"JavaS ...
- async/await的用法
es6 promise 静态方法+.all等待其他函数执行完再执行_心动止于人海.的博客-CSDN博客 https://segmentfault.com/a/1190000015488033 http ...
最新文章
- 揭秘 ClownFish 比手写代码还快的原因
- 机器学习-MNIST数据集-神经网络
- 驰骋工作流程引擎,ccflow,如何把子线程的数据汇总到合流节点表单中去?
- org.dom4j.DocumentException: null Nested exception: null解决方法
- 用VC写Assembly代码(5) --函数调用(一)
- Windows Server 2008 R2 搭建FTP服务
- 蓝桥杯 ADV-120算法提高 6-17复数四则运算
- Windows常用快捷键和Windows CMD命令大全
- OV5640_MIPI_1LEN调试记录
- SELECT 1 FROM DUAL中的DUAL的作用
- 栈的压入、弹出序列和栈所有可能的弹出顺序
- 【Python机器学习】回归模型:推土机售价预测
- 找字符串中最长单词C语言,C语言 在已知字符串中找最长单词
- 投机之王杰西·利弗莫尔的经典炒股语录
- 【限时删除】一个惊艳的神器,可全网爬取各种资源..........
- LruCache源码的理解
- 怎么看互联网反垄断下的大厂未来?
- python下载豆丁网文档
- Java命令行形式将程序打包成jar包
- 第一类修正贝塞尔函数[转]