一直对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的用法的更多相关文章

  1. 关于C#中async/await中的异常处理(下)-(转载)

    上一篇文章里我们讨论了某些async/await的用法中出现遗漏异常的情况,并且谈到该如何使用WhenAll辅助方法来避免这种情况.WhenAll辅助方法将会汇总一系列的任务对象,一旦其中某个出错,则 ...

  2. C#中async/await中的异常处理

    在同步编程中,一旦出现错误就会抛出异常,我们可以使用try-catch来捕捉异常,而未被捕获的异常则会不断向上传递,形成一个简单而统一的错误处理机制.不过对于异步编程来说,异常处理一直是件麻烦的事情, ...

  3. 关于C#中async/await中的异常处理(上)-(转载)

    在同步编程中,一旦出现错误就会抛出异常,我们可以使用try…catch来捕捉异常,而未被捕获的异常则会不断向上传递,形成一个简单而统一的错误处理机制.不过对于异步编程来说,异常处理一直是件麻烦的事情, ...

  4. [翻译] Python 3.5中async/await的工作机制

    Python 3.5中async/await的工作机制 多处翻译出于自己理解,如有疑惑请参考原文 原文链接 身为Python核心开发组的成员,我对于这门语言的各种细节充满好奇.尽管我很清楚自己不可能对 ...

  5. 关于C#中async/await中的异常处理(上)

    关于C#中async/await中的异常处理(上) 2012-04-11 09:15 by 老赵, 17919 visits 在同步编程中,一旦出现错误就会抛出异常,我们可以使用try…catch来捕 ...

  6. C# 中 async/await 调用传统 Begin/End 异步方法

    最近在改进园子的图片上传程序,希望实现用户上传图片时同时将图片文件保存在三个地方:1)服务器本地硬盘:2)又拍云:3)阿里云OSS.并且在保存时使用异步操作. 对于异步保存到本地硬盘,只需用 Stea ...

  7. async & await 的用法

    async 和 await 出现在C# 5.0之后,给并行编程带来了不少的方便,特别是当在MVC中的Action也变成async之后,有点开始什么都是async的味道了.但是这也给我们 编程埋下了一些 ...

  8. C# 异步操作 async await 的用法

    1. async与 await 成对出现 async 在方法前使用 ,方法体面面用  await . 2. 使用async 和await定义异步方法不会创建新线程. 3.await 后面一定是一个扫行 ...

  9. promise和async/await的用法

    promise和async都是做异步处理的, 使异步转为同步 1.promise 它和Promise诞生的目的都是为了解决“回调地狱”, promise使用方法: <button @click= ...

  10. async await的用法

    const fs = require('fs'); const readFile = function (fileName) { return new Promise(function (resolv ...

随机推荐

  1. Java安全之Resin2内存马

    Java安全之Resin2内存马 环境 resin2.1.17 添加Filter分析 依然是web.xml注册一个filter,debug进去看注册流程 debug dofilter逻辑时看到如下代码 ...

  2. 洛谷 P4135 作诗 题解

    题面. 之前做过一道很类似的题目 洛谷P4168蒲公英 ,然后看到这题很快就想到了解法,做完这题可以对比一下,真的很像. 题目要求区间内出现次数为正偶数的数字的数量. 数据范围1e5,可以分块. 我们 ...

  3. Go语言核心36讲19

    你好,我是郝林,今天我们继续分享go语句执行规则的内容. 在上一篇文章中,我们讲到了goroutine在操作系统的并发编程体系,以及在Go语言并发编程模型中的地位和作用等一系列内容,今天我们继续来聊一 ...

  4. ssh免交互

    sshpass -p the_password ssh -o StrictHostKeyChecking=no root@domainname_or_ip remote_command  #远程执行命 ...

  5. 【RocketMQ】顺序消息实现原理

    全局有序 在RocketMQ中,如果使消息全局有序,可以为Topic设置一个消息队列,使用一个生产者单线程发送数据,消费者端也使用单线程进行消费,从而保证消息的全局有序,但是这种方式效率低,一般不使用 ...

  6. 【Advanced Installer】打包winfrom程序出现您没有任何数字签名的实用程序。请安装平台 SDK。错误

    出现这个问题的原因是设置了磁铁,此功能只会在win8.1上有效.也就是开始菜单里面的磁铁图 只需要把这个删除掉就可以解决了

  7. LayuI 动态下拉框和动态设置选中

    动态下拉框 //下拉框异步加载 function asyncSelect(thisId, grade, selectNodeName) { $("#" + selectNodeNa ...

  8. 关于Module Not Found Error No module named Crypto解决

    前言 之前就遇到这个问题, 当然是windows上具有的问题 问题描述 from Crypto.Cipher import AES 出现 ModuleNotFoundError: No module ...

  9. MICCAI 论文投稿须知翻译

    MICCAI 论文投稿须知翻译 以MICCAI 2021 PAPER SUBMISSION AND REBUTTAL GUIDELINES为例,每年投稿须知类似 作者信息和rebuttal 本文件包含 ...

  10. VideoPipe可视化视频结构化框架更新总结(2022-12-9)

    项目地址:https://github.com/sherlockchou86/video_pipe_c 往期文章:https://www.cnblogs.com/xiaozhi_5638/p/1685 ...