栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > .Net

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

.Net 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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

深入理解 C# .NET Core 中 async await 异步编程思想
  • 引言
    • 一、什么是异步?
      • 1.1 简单实例(WatchTV并行CookCoffee)
    • 二、深入理解(异步)
      • 2.1 当我需要异步返回值时,怎么处理?
      • 2.2 充分利用异步并行的高效性
    • 三、 async await 的秘密

引言

很久没来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();

/// 
/// TV
/// 
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密广告结束了,好剧开始了!");
    });
}
/// 
/// Coffee
/// 
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 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 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 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 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自然就一点都不奇怪了!


转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1023094.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号