C# async 和 await 理解

C# async 和 await 理解

先假设如下场景:

主函数 Main,循环等待用户输入;

计算函数 Cal,耗时计算大量数据;

class Test
{
     static int Main(string[] args)
     {
        while(true)
        {
            // 等待用户输入
        }
     }

    public static int Cal() {
        int sum = 0;
        for (int i = 0; i < 999; i++)
        {
            sum = sum + i;
        }
        Console.WriteLine($"sum={sum}");
        return sum;
    }
}

为了在Main函数中调用Cal函数,同时Cal函数不阻塞主函数的循环,此时需要考虑增加一个CalAsync函数使Cal函数异步执行。

传统的思维方法  在CalAsync函数中启动一个线程,并在线程中执行Cal函数:

// using System.Threading;
public static CalAsync()
{
    Thread td = new Thread(new ThreadStart(Cal));
    td.start();
}

这种方法显示地创建了一个线程并启动执行,CalAsync函数本身还是在主线程执行并且无法直接获取Cal函数的结果。

async 和 await 异步编程方法  使用async标记CalAsync函数,并在CalAsync函数中创建任务Task异步执行Cal函数,同时使用await标记获取Cal函数的执行结果:

// using System.Threading.Tasks;
public static aysnc void CalAsync()
{
    int result = await Task.Run(new Func<int>(Cal));
    // 或使用lambda书写方式
    //  int result = await Task.Run(() => test());
    Console.WriteLine(result);
}

在Main函数中直接调用CalAsync函数,可以发现CalAsync成功调用了Cal函数并在一段时间后输出了结果,同时Main函数并不会被阻塞。

分别在Main、Cal、CalAsync函数中增加代码打印当前线程ID:

class Test
{
    static void Main(string[] args)
    {
        string tid = Thread.CurrentThread.ManagedThreadId.ToString();
        Console.WriteLine($"Main1 tid {tid}");
        Task<int> t = CalAsync();
        Console.WriteLine($"Main after CalAsync");
        Console.Read();
    }

    public static int Cal()
    {
        string tid = Thread.CurrentThread.ManagedThreadId.ToString();
        Console.WriteLine($"Cal tid {tid}");
        int sum = 0;
        for (int i = 0; i < 999; i++)
        {
            sum = sum + i;
        }
        Console.WriteLine($"sum={sum}");
        return sum;
    }

    public static async Task<int> CalAsync()
    {
        string tid = Thread.CurrentThread.ManagedThreadId.ToString();
        Console.WriteLine($"CalAsync1 tid {tid}");
        int result = await Task.Run(new Func<int>(Cal));
        tid = Thread.CurrentThread.ManagedThreadId.ToString();
        Console.WriteLine($"CalAsync2 tid {tid}, result={result}");
        return result;
    }
}

结果如图:

可以看出,在CalAsync函数中,await标记之前,代码在主线程中执行,而await标记之后,代码在子线程中执行。

理解与结论:

  • 在C#中, async标记了一个包含异步执行的函数,通过async标记的函数若在主线程中直接调用,则函数一开始仍在主线程中执行;
  • aysnc标记的函数内部必须包含await标记需要异步执行的函数(根据vs2017编译提示),若当前函数在主线程中直接调用,则await标记前的代码在主线程中执行,await标记后的代码在其异步子线程中执行;
  • async标记的函数返回值必须为void、Task、Task< TResult> 类型,可以理解为async标记的函数返回的是 “空”、“即将执行的任务”、“带结果的即将执行的任务”实例;
  • async标记的函数可以继续往下调用async标记函数,调用形式如下例, 从调用逻辑可以理解为await实际上用来触发所标记的Task任务异步执行,并最后获取异步执行的返回值,从运行过程看该触发应该仅对最终的Task任务有效:
 public static async Task<int> CallCalAsync()
        {
            string tid = Thread.CurrentThread.ManagedThreadId.ToString();
            Console.WriteLine($"CallCalAsync1 tid {tid}");
            int result = await CalAsync();
            tid = Thread.CurrentThread.ManagedThreadId.ToString();
            Console.WriteLine($"CallCalAsync2 tid {tid}, result={result}");
            return result;
        }

总结

C#中async与await异步编程,可以理解为:

1. async声明了一个包含异步执行代码的函数,该函数执行时不会阻塞调用线程;

2. await存在于async函数中,声明了一个异步执行入口,程序动态运行时从该入口创建并进入一个异步线程环境,并在该线程执行任务实例及任务实例返回之后的代码;

3. 一个async函数中声明多个await关键字时,程序将代码顺序创建并进入异步子线程执行任务实例及任务实例返回之后的代码直到下一个await声明处, 最后一个await声明之后的代码会在最后一个异步子线程中执行 ;

3. await标记的右侧代码返回或定义了一个任务实例,该实例由需要异步执行的目标耗时函数初始化,并在最终定义处触发异步执行。

原文地址:https://www.cnblogs.com/need/p/11288329.html

时间: 2024-10-11 21:10:33

C# async 和 await 理解的相关文章

对python async与await的理解

async/await关键字是出现在python3.4以后.网上已经有很多文章对async/await这两个关键字都有讲解,包括如何由python2的yield from发展到async/await这两个关键字,以及一些代码实现都有.但是对于像我这样初次接触的人来说,光看代码分析也不一定能理解,我也是在度娘上搜索很多相关的网站,当中也有官网,都没有发现能让我一眼看懂在什么地方可以用await,什么情况用await的文章.经过自己的重新思考,总算对async.await有一些初步的了解,所以想把自

Promise和async和await的理解

目录 1.回调函数直接作为函数参数 1.1传统的方式,使用jquery的get方法 语法 1.2 fetch方法 1.3 Promise方法 2.async和await的理解 1.回调函数直接作为函数参数 1.1传统的方式,使用jquery的get方法 语法 $.get(URL,data,function(data,status,xhr),dataType) 该方法里面可以设置回调函数,如下代码,可以在console窗口中直接执行,function(data)就代表get调用/数据请求之后的回调

第十五节:深入理解async和await的作用及各种适用场景和用法

一. 同步VS异步 1.   同步 VS 异步 VS 多线程 同步方法:需要等待返回结果,才可以继续往下执行业务 异步方法:无须等待返回结果,可以继续往下执行业务 开启新线程:在主线程之外开启一个新的线程去执行业务 同步方法和异步方法的本质区别: 是否需要等待返回结果才能继续执行业务 2. 常见的异步方法(都以Async结尾) ① HttpClient类:PostAsync.PutAsync.GetAsync.DeleteAsync ② EF中DbContext类:SaveChangesAsyn

【转】【C#】C# 5.0 新特性——Async和Await使异步编程更简单

一.引言 在之前的C#基础知识系列文章中只介绍了从C#1.0到C#4.0中主要的特性,然而.NET 4.5 的推出,对于C#又有了新特性的增加--就是C#5.0中async和await两个关键字,这两个关键字简化了异步编程,之所以简化了,还是因为编译器给我们做了更多的工作,下面就具体看看编译器到底在背后帮我们做了哪些复杂的工作的. 二.同步代码存在的问题 对于同步的代码,大家肯定都不陌生,因为我们平常写的代码大部分都是同步的,然而同步代码却存在一个很严重的问题,例如我们向一个Web服务器发出一个

Async和Await进行异步编程

使用Async和Await进行异步编程(C#版 适用于VS2015) 你可以使用异步编程来避免你的应用程序的性能瓶颈并且加强总体的响应.然而,用传统的技术来写异步应用是复杂的,同时编写,调试和维护都很困难. VS2012介绍了简单的方法,那就是异步编程,它在.Net Framework 4.5和Windows 运行时提供了异步支持.编译器做了开发者以前做的困难的工作,而且你的应用保持了类似于异步代码的逻辑结构.结果,你轻易地就获得了所有异步编程的优势. 异步提升响应 异步对于可能阻塞的活动是至关

c#之Async、Await剖析

c#之Async.Await剖析 探索c#之Async.Await剖析 2015-06-15 08:35 by 蘑菇先生, 1429 阅读, 5 评论, 收藏, 编辑 阅读目录: 基本介绍 基本原理剖析 内部实现剖析 重点注意的地方 总结 基本介绍 Async.Await是net4.x新增的异步编程方式,其目的是为了简化异步程序编写,和之前APM方式简单对比如下. APM方式,BeginGetRequestStream需要传入回调函数,线程碰到BeginXXX时会以非阻塞形式继续执行下面逻辑,完

使用Async和Await进行异步编程(C#版 适用于VS2015)

你可以使用异步编程来避免你的应用程序的性能瓶颈并且加强总体的响应.然而,用传统的技术来写异步应用是复杂的,同时编写,调试和维护都很困难. VS2012介绍了简单的方法,那就是异步编程,它在.Net Framework 4.5和Windows 运行时提供了异步支持.编译器做了开发者以前做的困难的工作,而且你的应用保持了类似于异步代码的逻辑结构.结果,你轻易地就获得了所有异步编程的优势. 异步提升响应 异步对于可能阻塞的活动是至关重要的.例如当你的应用访问Web的时候,访问web资源有时有点慢或者延

async和await关键字实现异步编程

async和await关键字实现异步编程 异步编程 概念 异步编程核心为异步操作,该操作一旦启动将在一段时间内完成.所谓异步,关键是实现了两点:(1)正在执行的此操作,不会阻塞原来的线程(2)一旦启动的此操作,可以继续执行其他任务.当该操作完成时,将调用回调函数来通知该操作已经结束. [注]:本人一直以为同步和异步都属于多线程的范畴,到今天才明白完全错误,异步和多线程是属于不同范畴,多线程和异步是并发的两种形式,并行处理和线程同步是多线程的两种形式,这是我当前的理解,不知是否有误,文中若有错误,

[C#]剖析异步编程语法糖: async和await

一.难以被接受的async 自从C#5.0,语法糖大家庭又加入了两位新成员: async和await. 然而从我知道这两个家伙之后的很长一段时间,我甚至都没搞明白应该怎么使用它们,这种全新的异步编程模式对于习惯了传统模式的人来说实在是有些难以接受,不难想象有多少人仍然在使用手工回调委托的方式来进行异步编程.C#中的语法糖非常多,从自动属性到lock.using,感觉都很好理解很容易就接受了,为什么偏偏async和await就这么让人又爱又恨呢? 我想,不是因为它不好用(相反,理解了它们之后是非常