关于C#中async/await的用法
一直对c#中async/await的用法模模糊糊,不太清晰,今天写了一下Demo彻底明确一下async/await的用法,以免因为对其不了解而对后期的业务产生影响(比如事务导致的锁表等等)。
1. 首先,async/await 一般是成对出现才有意义。其意义在于可以等待异步操作完成后继续顺序执行,而不是异步操作还没处理完成主线程就进行了下一步。
假设,我们现在要模拟简单的下载场景,首先用户点击下载,那么就调用DownloadHandle方法(异步)进行下载,然后通知用户下载完成。其使用 async/await 的区别如下:
(1)使用 async/await 的情况:
internal class Program
{
static void Main(string[] args)
{
DownloadHandle();
Console.ReadLine();
}
/// <summary>
/// 正常使用async/await时,符合正常的业务逻辑:
/// 1. 通知用户下载开始
/// 2. 异步下载
/// 3. 等待异步下载完成后给用户提示下载完成
/// </summary>
public static async void DownloadHandle()
{
Console.WriteLine("下载开始!->主线程ID:" + Thread.CurrentThread.ManagedThreadId);
await Download();
Console.WriteLine("下载完成!->主线程ID:" + Thread.CurrentThread.ManagedThreadId); }
/// <summary>
/// 下载
/// </summary>
/// <returns></returns>
public static Task Download()
{
return Task.Run(() =>
{
Console.WriteLine("下载线程ID:->" + Thread.CurrentThread.ManagedThreadId);
Console.WriteLine("10%");
Console.WriteLine("30%");
Console.WriteLine("50%");
Console.WriteLine("60%");
Console.WriteLine("80%");
Console.WriteLine("99%");
Console.WriteLine("100%");
});
}
}
结果如下:

可以看到,即时下载使用了异步(线程ID不同也表明了当前使用了异步),业务逻辑最终还是按照我们的需求,按顺序正序执行了。
(2)不使用async/await的情况:
internal class Program
{
static void Main(string[] args)
{
DownloadHandle();
Console.ReadLine();
}
/// <summary>
/// 不适用async/await时,则代码执行顺序时混乱的,不符合业务逻辑:
/// 1. 通知用户下载开始
/// 2. 提示下载完成
/// 3. 开始下载
/// </summary>
public static void DownloadHandle()
{
Console.WriteLine("下载开始!->主线程ID:" + Thread.CurrentThread.ManagedThreadId);
Download();
Console.WriteLine("下载完成!->主线程ID:" + Thread.CurrentThread.ManagedThreadId); }
/// <summary>
/// 下载
/// </summary>
/// <returns></returns>
public static Task Download()
{
return Task.Run(() =>
{
Console.WriteLine("下载线程ID:->" + Thread.CurrentThread.ManagedThreadId);
Console.WriteLine("10%");
Console.WriteLine("30%");
Console.WriteLine("50%");
Console.WriteLine("60%");
Console.WriteLine("80%");
Console.WriteLine("99%");
Console.WriteLine("100%");
});
}
}
结果如下:

可以看到,代码执行顺序混乱了,“下载完成” 跑到了 “下载线程ID” 前面去了,完全没有按照我们预期的顺序执行。
2. 如果可以await的方法不进行await,那将会怎样呢?
(1)如果被调用的异步方法内部使用了Task.Run,那结果可参考我们1中进行讲述的结果。开发者可根据实际需要来进行调用,如果异步方法的调用结果与其上下文逻辑没有严格的执行要求,则可以不进行await(比如记录日志等等)。反之,则需要加await。
(2)如果被调用的异步方法内部只是返回了Task.CompletedTask,即时使用了await/async实际上还是等于同步执行,如下图。
internal class Program
{
static void Main(string[] args)
{
DownloadHandle();
Console.ReadLine();
}
/// <summary>
/// 模拟下载
/// </summary>
public static async void DownloadHandle()
{
Console.WriteLine("下载开始!->主线程ID:" + Thread.CurrentThread.ManagedThreadId);
await Download();
Console.WriteLine("下载完成!->主线程ID:" + Thread.CurrentThread.ManagedThreadId); }
/// <summary>
/// 下载
/// </summary>
/// <returns></returns>
public static Task Download()
{
Console.WriteLine("下载线程ID:->" + Thread.CurrentThread.ManagedThreadId);
Console.WriteLine("10%");
Console.WriteLine("30%");
Console.WriteLine("50%");
Console.WriteLine("60%");
Console.WriteLine("80%");
Console.WriteLine("99%");
Console.WriteLine("100%");
return Task.CompletedTask;
}
结果如图:

可以看到,即使DonwloadHandle方法使用了await/async,还是进行了同步执行,并没有异步效果(可从所有线程ID相同看出)
3. 小技巧: 异步方法的返回值类型一般都是Task或者Task<T>类型的,当返回值为Task时(即方法的返回值类型为void),我们可以直接return Task.Run(()=>{})(以下第一段代码),而不必await Task.Run(()=>{})(以下第二段代码),这样也可从一定程度上提高代码执行效率。
/// <summary>
/// 下载
/// </summary>
/// <returns></returns>
public static Task Download()
{
return Task.Run(() =>
{
Console.WriteLine("下载线程ID:->" + Thread.CurrentThread.ManagedThreadId);
Console.WriteLine("10%");
Console.WriteLine("30%");
Console.WriteLine("50%");
Console.WriteLine("60%");
Console.WriteLine("80%");
Console.WriteLine("99%");
Console.WriteLine("100%");
});
}
/// <summary>
/// 下载
/// </summary>
/// <returns></returns>
public static async Task Download()
{
await Task.Run(() =>
{
Console.WriteLine("下载线程ID:->" + Thread.CurrentThread.ManagedThreadId);
Console.WriteLine("10%");
Console.WriteLine("30%");
Console.WriteLine("50%");
Console.WriteLine("60%");
Console.WriteLine("80%");
Console.WriteLine("99%");
Console.WriteLine("100%");
});
}
以上,只是作者的个人理解,请大神勿喷,如有错误,欢迎指正,谢谢!
关于C#中async/await的用法的更多相关文章
- 关于C#中async/await中的异常处理(下)-(转载)
上一篇文章里我们讨论了某些async/await的用法中出现遗漏异常的情况,并且谈到该如何使用WhenAll辅助方法来避免这种情况.WhenAll辅助方法将会汇总一系列的任务对象,一旦其中某个出错,则 ...
- C#中async/await中的异常处理
在同步编程中,一旦出现错误就会抛出异常,我们可以使用try-catch来捕捉异常,而未被捕获的异常则会不断向上传递,形成一个简单而统一的错误处理机制.不过对于异步编程来说,异常处理一直是件麻烦的事情, ...
- 关于C#中async/await中的异常处理(上)-(转载)
在同步编程中,一旦出现错误就会抛出异常,我们可以使用try…catch来捕捉异常,而未被捕获的异常则会不断向上传递,形成一个简单而统一的错误处理机制.不过对于异步编程来说,异常处理一直是件麻烦的事情, ...
- [翻译] Python 3.5中async/await的工作机制
Python 3.5中async/await的工作机制 多处翻译出于自己理解,如有疑惑请参考原文 原文链接 身为Python核心开发组的成员,我对于这门语言的各种细节充满好奇.尽管我很清楚自己不可能对 ...
- 关于C#中async/await中的异常处理(上)
关于C#中async/await中的异常处理(上) 2012-04-11 09:15 by 老赵, 17919 visits 在同步编程中,一旦出现错误就会抛出异常,我们可以使用try…catch来捕 ...
- C# 中 async/await 调用传统 Begin/End 异步方法
最近在改进园子的图片上传程序,希望实现用户上传图片时同时将图片文件保存在三个地方:1)服务器本地硬盘:2)又拍云:3)阿里云OSS.并且在保存时使用异步操作. 对于异步保存到本地硬盘,只需用 Stea ...
- async & await 的用法
async 和 await 出现在C# 5.0之后,给并行编程带来了不少的方便,特别是当在MVC中的Action也变成async之后,有点开始什么都是async的味道了.但是这也给我们 编程埋下了一些 ...
- C# 异步操作 async await 的用法
1. async与 await 成对出现 async 在方法前使用 ,方法体面面用 await . 2. 使用async 和await定义异步方法不会创建新线程. 3.await 后面一定是一个扫行 ...
- promise和async/await的用法
promise和async都是做异步处理的, 使异步转为同步 1.promise 它和Promise诞生的目的都是为了解决“回调地狱”, promise使用方法: <button @click= ...
- async await的用法
const fs = require('fs'); const readFile = function (fileName) { return new Promise(function (resolv ...
随机推荐
- 【RPC和Protobuf】之RPC入门
一,概念 RPC:Remote procedure call(远程过程调用),分布式系统中不同节点之间流行的通信方式 服务端: 注: 1.执行下面的代码之后,会相应的启动一个tcp进程 C:\User ...
- day20-web开发会话技术02
WEB开发会话技术02 6.Cookie的生命周期 默认情况下,Cookie只在浏览器的内存中存活,也就是说,当你关闭浏览器后,Cookie就会消失.但是也可以通过方法设置cookie的生存时间. c ...
- 记录下批处理bat脚本获取打包发布问题
最近做了个Jenkins配合Gitlab自动部署Java项目到Windows Server服务器. Jenkins和Gitlab在Linux下,好一顿折腾,先记录下脚本,其余后续补充吧. 把Java项 ...
- layui table表格使用table.resize()方法 重置表格尺寸
解决 使用layui中的table表格重置表格尺寸 问题 表格的高度共有两种写法 相对应的就有两种解决方法 第一种 当表格高度设置为固定高度时,改变表格高度使用 tableIns=table.rend ...
- 【Devexpres】spreadsheetControl自动列宽
Worksheet worksheet = this.spreadsheetControl1.ActiveWorksheet; worksheet.Import(datatable, true, 0, ...
- npm 依赖下载报错:主机名/IP与证书的altname不匹配
npm 依赖下载报错:主机名/IP与证书的altname不匹配: //取消ssl验证 npm set strict-ssl false npm config set registry http://r ...
- vue3 第二天vue响应式原理以及ref和reactive区别
前言: 前天我们学了 ref 和 reactive ,提到了响应式数据和 Proxy ,那我们今天就来了解一下,vue3 的响应式 在了解之前,先复习一下之前 vue2 的响应式原理 vue2 的响应 ...
- Google Chrome(谷歌浏览器)安装使用
谷歌浏览器官网https://www.google.cn/chrome/ Chrome是由Google开发的一款简单便捷的网页浏览工具.谷歌浏览器(Google Chrome)可以提帮助你快速.安全的 ...
- day28-jQuery01
jQuery01 参考文档1:jQuery API 中文文档 | jQuery API 中文在线手册 | jquery api 下载 | jquery api chm (cuishifeng.cn) ...
- 【Spark】Day01-入门、模块组成、4种运行模式详解及配置、案例实操(spark分析过程)
一.概述 1.概念 基于内存的大数据分析计算引擎 2.特点 快速.通用.可融合性 3.Spark内置模块[腾讯8000台spark集群] Spark运行在集群管理器(Cluster Manager)上 ...