async/await Task.Delay 和Thread.Sleep的理解

相关学习资料:

第十七节:从状态机的角度async和await的实现原理(新) - Yaopengfei - 博客园 (cnblogs.com)

[基础知识]有限状态机_哔哩哔哩_bilibili

C# async await 原理:编译器如何将异步函数转换成状态机 | 码农网 (codercto.com)

await——调用的等待期间,.NET会把当前的线程返回给线程池,等异步方法调用执行完毕后,框架会从线程池再取出来一个线程执行后续的代码,当前线程不会阻塞

从原理层面刨析

  1. async与await是语法糖,最终译成“状态机调用”。其他常用的语法糖var、using、lambda表达式等。

  2. async关键字标记的方法会被C#编译器编译成一个状态机。

  3. await是关键字是为了实现状态机中的一个状态。

    会根据方法内的await调用切分成多个状态,每当有一个await,就会生成一个对应的状态。

  4. 状态机实现了AsyncStateMachine接口,里面有MoveNext 和 SetStateMachine方法处理相应业务.

    MoveNext——定义各个状态之间转换的方法

    1. 在await执行时调用一次,在await操作结束时继续调用

从实践方向刨析

  1. async会将方法的返回结果包装成Task,所以它不是必需的

            //使用async,实际是将Result包装成Task<Result>
    //此处就是对结果通过await拆包,再通过async包装成Task<Result>返回,当前场景下没有必要,可直接简写成下面的场景
    public static async Task AsyncNoReturn()
    {
    await Task.Delay(500);
    }
    //不使用async的写法,因为类型已经是Task了不需要通过async关键字包装
    public static Task AsyncNoReturn1()
    {
    return Task.Delay(500);
    }

    总结:如果一个异步方法只是对别的异步方法调用的转发,并没有太多复杂的逻辑(比如等待的结果,再调用B:把调用的返回值拿到内部做一些处理再返回),那么就可以去掉async关键字。返回值为Task的方法不一定都要标注async,标注async只是让我们可以更方便的await而已

    1. 避免对返回结果Task的“拆包后再次包装”
    2. 避免在底层创建状态机,性能更优

    正面Demo:

            public static Task<string> DownloadFromFile(int num)
    {
    if (num == 1)
    {
    return File.ReadAllTextAsync(@"D:\1.txt");
    }
    else if (num == 2)
    {
    return File.ReadAllTextAsync(@"D:\2.txt");
    }
    else
    {
    throw new ArgumentException("Invalid Number");
    }
    }

    如果没有在声明Task的时候前面没有加await,则主线程不会异步等待Task完成,主线程会继续往下执行,与Task并发执行

    Task.Delay() 和 Thread.Sleep() 区别

Thread.Sleep() ——会让当前线程休眠,形成阻塞,当前休眠结束后继续往下执行

await Task.Delay()——当前线程返回线程池,从线程池拿另外一个空闲线程线程做定时任务,等待任务结束后,从线程池拿到一个空闲线程,继续往下执行。

            await Task.Delay(200);
//可理解等效成如下代码
await Task.Run(() =>
{
Thread.Sleep(200);
});

区别:

  1. Thread.Sleep会阻塞当前线程,但是从线程池另取线程;Task.Delay不会阻塞当前线程,但是会新取一个线程

  2. Thread.Sleep不可取消,Task.Delay可取消

            public static Task Test_Delay()
    {
    //创建一个5秒的异步等待
    Task delay1 = Task.Delay(TimeSpan.FromSeconds(5));
    return delay1;
    }

    在Main方法里测试

    static void Main(string[] args)
    {
    //Task在声明处就开始执行
    var test = Test_Delay();
    //主线程等待2秒钟
    Thread.Sleep(TimeSpan.FromSeconds(2));
    Stopwatch sw = new Stopwatch();
    sw.Start();
    //当前线程等待test指向的Task执行结束
    test.Wait();
    sw.Stop();
    TimeSpan ts = sw.Elapsed;
    Console.WriteLine($"Task.Delay执行结束,耗时:{ts.TotalMilliseconds}");
    Console.ReadKey();
    }

    结果打印:

    Task.Delay执行结束,耗时:3004.527

    上面显示大概监听为3秒。这个表示了当前主线程在运行的时候,Task.Delay也在运行,这个只有在不同线程才可以实现。

async/await Task.Delay 和Thread.Sleep的理解的更多相关文章

  1. async/await Task Timeout

    async/await Task Timeout 在日常的电脑使用过程中,估计最难以忍受的就是软件界面"卡住""无响应",在我有限的开发生涯中一直都是在挑战 它 ...

  2. Task C# 多线程和异步模型 TPL模型 【C#】43. TPL基础——Task初步 22 C# 第十八章 TPL 并行编程 TPL 和传统 .NET 异步编程一 Task.Delay() 和 Thread.Sleep() 区别

    Task C# 多线程和异步模型 TPL模型   Task,异步,多线程简单总结 1,如何把一个异步封装为Task异步 Task.Factory.FromAsync 对老的一些异步模型封装为Task ...

  3. async await Task

    一.使用Task 引用命名空间 using System.Threading.Tasks; 1.工厂方式 Task.Factory.StartNew(() => {Console.WriteLi ...

  4. async,await,Task 的一些用法

    async,await,Task 的一些用法 private void Form1_Load(object sender, EventArgs e) { Display(); } public asy ...

  5. C#扫盲篇(四):.NET Core 的异步编程-只讲干货(async,await,Task)

    关于async,await,task的用法和解释这里就不要说明了,网上一查一大堆.至于为啥还要写这篇文章,主要是其他文章水分太多,不适合新手学习和理解.以下内容纯属个人理解,如果有误,请高手指正.本文 ...

  6. c#5.0(.net 4.5之后)的 Async+await+Task的异步机制的调试笔记

    1.)无返回值的情况(异步也是基于线程). using System; using System.Collections.Generic; using System.Linq; using Syste ...

  7. Task.Delay() 和 Thread.Sleep() 区别

    1.Thread.Sleep 是同步延迟,Task.Delay异步延迟. 2.Thread.Sleep 会阻塞线程,Task.Delay不会. 3.Thread.Sleep不能取消,Task.Dela ...

  8. task.delay 和 thread.sleep

    1.Thread.Sleep 是同步延迟. Task.Delay异步延迟. 2.Thread.Sleep 会阻塞线程,Task.Delay不会. 3.Thread.Sleep不能取消,Task.Del ...

  9. async await Task 使用方法

    使用概述 C#的使用过程中,除了以前的Thread.ThreadPool等用来开一个线程用来处理异步的内容.还可以使用新特性来处理异步.比以前的Thread和AutoResetEvent.delege ...

  10. async await task.Result 卡死

    在如下代码中: public async Task<string> GetData() { return await DoWork(); } 在UI线程中调用 var data = Get ...

随机推荐

  1. 第一!天翼云领跑中国边缘云laaS市场!

    近日,弗若斯特沙利文(Frost & Sullivan,简称"沙利文")联合头豹研究院发布<2023年中国边缘云市场报告>,天翼云在2023H1中国边缘云Iaa ...

  2. 释放全球互连的数字潜力!MWC 2024云网高峰论坛召开,中国电信天翼云扬帆起航!

    2月27日,在2024年世界移动通信大会(MWC 2024)期间,中国电信云网高峰论坛顺利召开.本次论坛以"释放全球互连的数字潜力"为主题,汇聚全球多个国家和地区的通信业领袖和重量 ...

  3. Rocksdb原理简介

    本文分享自天翼云开发者社区<Rocksdb原理简介>,作者:l****n Rocksdb作为当下nosql中性能的代表被各个存储组件(mysql.tikv.pmdk.bluestore)作 ...

  4. 解决Git拉取出现“bad config line 1 in file C:\Users\quber/.gitconfig”的错误

    1.问题描述 我们在拉取Git项目的时候,突然出现如下图所示的错误提示: 2.解决办法 定位到.gitconfig文件,然后将其删除掉: 然后在项目文件夹中点击鼠标右键,选择Git Bash Here ...

  5. PHP变量与变量作用域

    PHP变量与变量作用域 1. 变量的基本概念 在PHP中,变量用于存储各种类型的数据,如字符串.整数.浮点数.布尔值.数组和对象等.变量名以美元符号$开头,后面跟着一个或多个字符(变量名).例如: & ...

  6. NIT GREAT NITYACKE DESTROYS THE UNIVERSE

    线段树 一般线段树维护的东西是什么?设其维护的信息的半群 \((A,+)\),维护标记的半群 \((T,\times)\) 和一种运算 \(*\mapsto A*T\to A\). 要求 \((b+c ...

  7. FLink写入Clickhouse优化

    一.背景 ck因为有合并文件操作,适合批量写入.如单条插入则速度太慢 二.Flink写入ck优化 改为分批插入,代码如下 DataStream<Row> stream = ... stre ...

  8. jenkins+svn+tomcat

    1.安装插件即可在源码管理中看见svn的选项subversion2.源码管理中配置svn的工程地址 3.点击Credentials的[添加]配置svn的用户名密码,完成后选取即可 4.配置构建触发器, ...

  9. win - [01] 修改网络连接名称(网络1、网络2...网络10)

    修改网络连接的名称 1.打开运行窗口:Windows 键 + R 2.在运行窗口输入 regedit,打开注册表编辑器 3.在 HKEY_LOCAL_MACHINE\SOFTWARE\Microsof ...

  10. DeepSeek 不太稳定?那就搭建自己的 DeepSeek 服务

    概述 DeepSeek-R1 发布 DeepSeek 在 2025 年给我们送来一份惊喜,1 月 20 号正式发布第一代推理大模型 DeepSeek-R1.这个模型在数学推理.代码生成和复杂问题解决等 ...