当前位置:首页 > 技术分析 > 正文内容

对于async和await的使用方式、作用效果不理解 ?没关系,看这篇

ruisui884个月前 (02-14)技术分析17

结论

同步还是异步,区别如下:

  • 同步:你使用 await 修饰符去调用一个异步(async)方法(是异步方法,不过是阻塞式的,可简单理解为同步);
  • 异步:你获取异步方法返回的 Task,就是异步(后文有代码示例);
  • 可以实现多任务执行顺序执行且不阻塞。

概述

async(C# 参考)

async 是“异步”的简写,使用 async 修饰符可将方法、lambda 表达式或匿名方法指定为异步。

如果对方法或表达式使用此修饰符,则其称为异步方法 。

如下示例定义了一个名为 ExampleMethodAsync 的异步方法:

public async Task ExampleMethodAsync()
{
    //...
}

await(C# 参考)

await 运算符暂停对其所属的 async 方法的求值,直到其操作数表示的异步操作完成。

异步操作完成后,await 运算符将返回操作的结果(如果有)。

await 运算符应用到表示已完成操作的操作数时,它将立即返回操作的结果,而不会暂停其所属的方法。

await 运算符不会阻止计算异步方法的线程。

await 运算符暂停其所属的异步方法时,控件将返回到方法的调用方。

官网说的话是不是听不明白?没关系,你就理解为添加了await 修饰符后,必须要等调用返回后才能继续执行下一步。

如下示例:

public async Task ExampleMethodAsync()
{
    //...
    //这添加了await,执行到这里需要等待MethodAwiat方法执行完成后才会往下继续执行。
    int result = await MethodAwiat();
    //...

}
public async Task MethodAwiat()
{
    //...
}

作用及基本用法

await和async可以简化我们异步编程,也可以让我们以一种类似同步编程的方式来进行异步编程。

另外当我们需要不阻塞主线程异步执行,但又要有顺序的执行相关代码的时候,await/async就可以排上用场。

基本用法如下示例:

        /// 
        /// 可异步可同步
        /// 
        /// 
        public  async Task TestAsync()
        {
            Thread.Sleep(3000);
            Task task = new Task(() =>
            {
                return "主程序返回后我还在执行数据:我是复杂的异步执行的方法,不阻碍主程序执行。。。。。";
            });
            task.Start();
            return await task;
        }

        // await 使得任务同步
        public  async void T1()
        {
            // 使用 await 关键字,代表等待执行完成,同步
            string time = await TestAsync();
            Console.WriteLine(time);
            Console.WriteLine("执行完毕");
        }

        // 直接获得返回的 Task,实现异步
        public  void T2()
        {
            // 获取 Task 任务对象,后面的逻辑过程可以弄成异步
            Task task = TestAsync();

            // 这里可以处理其它事情,处理完毕后,再获取执行结果
            Console.WriteLine("执行完毕");

            Console.WriteLine(task.Result);
        } 

实现多任务顺序执行且不阻塞

以微软文档的做早餐的案例加以简化来讲解 【使用Async和Await可以实现多任务顺序执行且不阻塞】。

主线任务任务:倒橙汁 -> 烤面包 -> 煎培根 -> 煎鸡蛋 -> 倒咖啡。

1.同步执行

我们任务逐步顺序执行如下,耗时:17064毫秒(17.064秒):

using Microsoft.International.Converters.TraditionalChineseToSimplifiedConverter;
using System;
using System.Diagnostics;
using System.Threading;

namespace ConsoleApp1
{
    class Program
    {

        static void Main(string[] args)
        {
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            PourOJ();
            PourCoffee();
            ToastBread();
            FryBacon();
            FryEggs();
            Console.WriteLine("早餐已经做完!");
            stopwatch.Stop();
            Console.WriteLine($"做早餐总计耗时:{stopwatch.ElapsedMilliseconds}");
            Console.ReadLine();

        }

        //倒橙汁
        private static void PourOJ()
        {
            Thread.Sleep(1000);
            Console.WriteLine("倒一杯橙汁");
        }

        //烤面包
        private static void ToastBread()
        {
            Console.WriteLine("开始烤面包");
            Thread.Sleep(3000);
            Console.WriteLine("烤面包好了");

        }

        //煎培根
        private static void FryBacon()
        {
            Console.WriteLine("开始煎培根");
            Thread.Sleep(6000);
            Console.WriteLine("培根煎好了");
        }
        //煎鸡蛋
        private static void FryEggs()
        {
            Console.WriteLine("开始煎鸡蛋");
            Thread.Sleep(6000);
            Console.WriteLine("鸡蛋好了");
        }

        //倒咖啡
        private static void PourCoffee()
        {
            Thread.Sleep(1000);
            Console.WriteLine("倒咖啡");
        }
    }
}

2.并行执行

如果此时我们每一项任务都有一个单独的人去完成,将会缩短时间将近3倍(当然不能单纯的用时间量化他),

如下,耗时6041毫秒(6.041秒):

using Microsoft.International.Converters.TraditionalChineseToSimplifiedConverter;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {

        static void Main(string[] args)
        {
            Test();
            Console.ReadLine();

        }

        private static void Test()
        {
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            List tasks = new List() { PourOJ(), ToastBread(), FryBacon(), FryEggs(), PourCoffee() };
            Task.WhenAll(tasks).ContinueWith((t) =>
            {
                Console.WriteLine("早餐已经做完!");
                stopwatch.Stop();
                Console.WriteLine($"做早餐总计耗时:{stopwatch.ElapsedMilliseconds}");
            });
        }

        //倒橙汁
        private static async Task PourOJ()
        {
            await Task.Delay(1000);
            Console.WriteLine("倒一杯橙汁");
        }

        //烤面包
        private static async Task ToastBread()
        {
            Console.WriteLine("开始烤面包");
            await Task.Delay(3000);
            Console.WriteLine("烤面包好了");

        }

        //煎培根
        private static async Task FryBacon()
        {
            Console.WriteLine("开始煎培根");
            await Task.Delay(6000);
            Console.WriteLine("培根煎好了");
        }
        //煎鸡蛋
        private static async Task FryEggs()
        {
            Console.WriteLine("开始煎鸡蛋");
            await Task.Delay(6000);
            Console.WriteLine("鸡蛋好了");
        }

        //倒咖啡
        private static async Task PourCoffee()
        {
            await Task.Delay(1000);
            Console.WriteLine("倒咖啡");
        }
    }
}

3.并行且可指定顺序执行

但是我们不可能每次做早餐都有那么多人同时做,

需求变更:如果现在要求,先倒橙汁,然后倒咖啡,其余的操作并行执行,应该如何操作呢?

只需将以上案例的主线程Test 方法修改如下,其他的不变,耗时8073毫秒(8.073秒):

private static async void Test()
        {
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            await PourOJ();             //倒橙汁
            await PourCoffee();         //然后倒咖啡
            List tasks = new List() { ToastBread(), FryBacon(), FryEggs() };//子任务List
            await Task.WhenAll(tasks);  //其余的并行操作
            Console.WriteLine("早餐已经做完!");
            stopwatch.Stop();
            Console.WriteLine($"做早餐总计耗时:{stopwatch.ElapsedMilliseconds}");
        }

总结

我们发现,用好了async和await确实很节省时间。

大家可以想想怎么优雅的在异步里面开多线程(多主线程多子线程)最节省时间。


原文链接:
https://www.cnblogs.com/xiongze520/p/16976940.html

扫描二维码推送至手机访问。

版权声明:本文由ruisui88发布,如需转载请注明出处。

本文链接:http://www.ruisui88.com/post/1946.html

标签: aysnc
分享给朋友:

“对于async和await的使用方式、作用效果不理解 ?没关系,看这篇” 的相关文章

Gitlab概览

Gitlab是开源的基于Git的仓库管理系统,也可以管理软件开发的整个生命周期,是项目管理和代码托管平台,支撑着整个DevOps的生命周期。Gitlab很容易选为GitHub,作为公司私有库管理的工具。我们可以用Gitlab Workflow来协同整个团队的软件开发管理过程。软件开发阶段Gitlab...

理解virt、res、shr之间的关系(linux系统篇)

前言想必在linux上写过程序的同学都有分析进程占用多少内存的经历,或者被问到这样的问题——你的程序在运行时占用了多少内存(物理内存)?通常我们可以通过top命令查看进程占用了多少内存。这里我们可以看到VIRT、RES和SHR三个重要的指标,他们分别代表什么意思呢?这是本文需要跟大家一起探讨的问题。...

软件测试-性能测试专题方法与经验总结

本文 从 性能测试流程,性能测试指标,性能监测工具,性能测试工具,性能测试基线,性能测试策略,性能瓶颈分析方法几个维度,进行知识总结和经验分享;详细见下图总结,欢迎大家补充;性能测试经验与思考1. 性能测试流程1.1. 性格规格评审1.2. 资源排期1.2.1. 人力资源1.2.2. 时间计划· 性...

K8S NFS 共享存储

NFS 共享存储前面我们学习了 hostPath 与 Local PV 两种本地存储方式,但是平时我们的应用更多的是无状态服务,可能会同时发布在不同的节点上,这个时候本地存储就不适用了,往往就需要使用到共享存储了,比如最简单常用的网络共享存储 NFS,本节课我们就来介绍下如何在 Kubernetes...

2024最新版:前端性能优化方案汇总

前端训练营:1v1私教,终身辅导计划,帮你拿到满意的 offer。 已帮助数百位同学拿到了中大厂 offer。欢迎来撩~~~~~~~~Hello,大家好,我是 Sunday。前端性能优化一直是很多同学非常关注的问题,在日常的面试中也是经常会被问到的点。所以今天咱们就花一点时间来了解一下2024最新的...

Python中的11 种数组算法

1. 创建数组 创建数组意味着留出一个连续的内存块来存储相同类型的元素。在大多数语言中,您可以在创建数组时指定数组的大小。假设您正在书架上整理一组书籍,并且您需要为正好 10 本书预留空间。功能架上的每个空间都对应于数组中的一个索引。# Example in Python arr = [1, 2,...