深入理解 C# .NET Core 中 async await 异步编程思想

本文深入探讨C# .NET Core中的异步编程,通过WatchTV和CookCoffee的实例解释异步的概念,展示了如何在需要返回值时使用async/await,以及如何充分利用异步并行的高效性。通过分析代码,揭示了async/await在任务切换中的秘密,帮助读者更好地理解和应用异步编程。
摘要由CSDN通过智能技术生成

引言

很久没来CSDN了,快小半年了一直在闲置,主要是因为一时写不出一些稍微带有思想和深度的文章;之前就写过一篇关于async await 的异步理解 ,现在回顾,描述的并不到位、理解得也不透彻!好了,废话不多说了,直入主题吧!

一、什么是异步?

我们采用最简单的方式来描述吧,如同:当我们回到家打开电视机后,我们同时还可以烧热水,煮杯咖啡!当咖啡煮好了,好看的电视剧也开始了,在等待好看的电视进行播放和煮咖啡这个过程是同时执行的,所以我们才能在电视播放的同时一边喝咖啡一边品好剧;这种高效的处理方式,我们把它叫做异步!官方实例(特别生动形象的一个例子)

在这里插入图片描述

1.1 简单实例(WatchTV并行CookCoffee)

// See https://aka.ms/new-console-template for more information
var watchTV = WatchTV();//TV
var cookCoffee=CookCoffee();//Coffee
Console.ReadKey();

/// <summary>
/// TV
/// </summary>
static Task WatchTV()
{
    return Task.Run(() =>
    {
        Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}:脑白金广告开始了!");
        Thread.Sleep(2000);
        Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}:脑白金广告结束了,大宝SOD密广告开始了!");
        Thread.Sleep(2000);
        Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}:大宝SOD密广告结束了,好剧开始了!");
    });
}
/// <summary>
/// Coffee
/// </summary>
static Task CookCoffee()
{
    return Task.Run(() =>
    {
        Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}:开始烧水了!");
        Thread.Sleep(2000);
        Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}:水烧开了,开始煮咖啡了!");
        Thread.Sleep(2000);
        Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}:咖啡煮好了,好剧开始了,准备一边喝咖啡一边品剧了!");
    });
}

注意看,最巧妙的地方就在于,相同的时间,广告播放完了,而我的咖啡也煮好了!异步,实质上就是相同的时间我可以同时完成很多件事,就像我们煮咖啡的时候,什么爱奇艺、优酷、腾讯…讨厌的大段广告已经播放完了呀,简直不要太nice,yyds

在这里插入图片描述

二、深入理解(异步)

2.1 当我需要异步返回值时,怎么处理?

简单,通过awiat,即可得到我们想要的运行结果,那我们简单改造下代码,加个返回值:

var watchTV = await WatchTV();//TV
Console.WriteLine(watchTV);
var cookCoffee=await CookCoffee();//Coffee
Console.WriteLine(cookCoffee);
Console.ReadKey();
static Task<string> WatchTV()
{
    return Task.Run(() =>
    {
        Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}:脑白金广告开始了!");
        Thread.Sleep(2000);
        Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}:脑白金广告结束了,大宝SOD密广告开始了!");
        Thread.Sleep(2000);
        return $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}:大宝SOD密广告结束了,好剧开始了!";
    });
}
static Task<string> CookCoffee()
{
    return Task.Run(() =>
    {
        Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}:开始烧水了!");
        Thread.Sleep(2000);
        Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}:水烧开了,开始煮咖啡了!");
        Thread.Sleep(2000);
       return $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}:咖啡煮好了,好剧开始了,准备一边喝咖啡一边品剧了!";
    });
}

这里注意了,怎么感觉好像回到了同步,因为这时候,好像已经不再是异步,它在一步一步地执行,明明是异步的写法,怎么成了同步的效果,这到底怎么回事?

在这里插入图片描述

其实,官方早已有了解释,也就是说,这时候虽然有了await关键字,线程是不会阻塞,但实际耗时却和同步是一样,但是要注意,这时候任然是异步,千万别理解成回归同步了,因为只是没有利用异步的关键功能!

在这里插入图片描述

2.2 充分利用异步并行的高效性

我们继续进行代码改造,因为上述的操作只是因为没有同时进行任务启动,那我们就改成同时进行任务启动吧!这样,就得到我们想要的结果了,既异步并行了,我们又拿到了自己想要返回值,简直不要太爽!

// See https://aka.ms/new-console-template for more information
var watchTv=WatchTV();//TV
var cookCoffee=CookCoffee();//Coffee
Console.WriteLine(await watchTv);
Console.WriteLine(await cookCoffee);
Console.ReadKey();

在这里插入图片描述

三、 async await 的秘密

注意看下面这段代码和运行结果,怎么好像主线程Id怎么被切换成子线程Id了呢?

// See https://aka.ms/new-console-template for more information
Console.WriteLine("MainId:" + Thread.CurrentThread.ManagedThreadId);
var watchTv = WatchTV();//TV
var cookCoffee = CookCoffee();//Coffee
Console.WriteLine(await watchTv);
Console.WriteLine(await cookCoffee);
Console.WriteLine("MainId:" + Thread.CurrentThread.ManagedThreadId);
Console.ReadKey();
static Task<string> WatchTV()
{
    return Task.Run(() =>
    {
        Console.WriteLine("Tv:" + Thread.CurrentThread.ManagedThreadId);
        Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}:脑白金广告开始了!");
        Thread.Sleep(2000);
        Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}:脑白金广告结束了,大宝SOD密广告开始了!");
        Thread.Sleep(2000);
        return $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}:大宝SOD密广告结束了,好剧开始了!";
    });
}
static Task<string> CookCoffee()
{
    return Task.Run(() =>
    {
        Console.WriteLine("Coffee:" + Thread.CurrentThread.ManagedThreadId);
        Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}:开始烧水了!");
        Thread.Sleep(2000);
        Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}:水烧开了,开始煮咖啡了!");
        Thread.Sleep(2000);
        return $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}:咖啡煮好了,好剧开始了,准备一边喝咖啡一边品剧了!";
    });
}

在这里插入图片描述

这是怎么回事呢?让我们来仔细分析分析?起初我怎么都想不明白,后来终于在 官网 找到答案,最简单直白地说:当异步 async await 遇到 await 时,异步任务会移交控制权,让步于调用方await 异步任务完成后,但Main(主线程)还没做完呀,仍在异步线程中答案“异步任务执行运算的同时,允许其他任务在当前线程执行”所以这时候当前线程成了异步线程Id自然就一点都不奇怪了!

在这里插入图片描述
在这里插入图片描述

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值