首页 > 编程语言 >异步编程 async与await

异步编程 async与await

时间:2022-12-12 15:24:07浏览次数:60  
标签:异步 Task Console await WriteLine async

原文链接:http://t.zoukankan.com/itjeff-p-4424810.html

原文链接:https://learn.microsoft.com/zh-cn/dotnet/csharp/whats-new/csharp-version-history

C# 5.0 版

C# 版本 5.0 随 Visual Studio 2012 (.Net Framework 4.5)一起发布,是该语言有针对性的一个版本。

对此版本中所做的几乎所有工作都归入另一个突破性语言概念:适用于异步编程的 async 和 await 模型。 下面是主要功能列表:

但是 async 和 await 才是此版本真正的主角。

C# 在 2012 年推出这些功能时,将异步引入语言作为最重要的组成部分,另现状大为改观。

如果你以前处理过冗长的运行操作以及实现回调的 Web,应该会爱上这项语言功能。

先来看个传统同步方法例子:

using System.Threading;
using System;

public class Program
{
    static void Main(string[] args)
    {
        // 同步方式
        Console.WriteLine("同步方式测试开始!");
        SyncMethod(0);
        Console.WriteLine("同步方式结束!");
        Console.ReadKey();
    }

    // 同步操作
    private static void SyncMethod(int input)
    {
        Console.WriteLine("进入同步操作!");
        var result = SyancWork(input);
        Console.WriteLine("最终结果{0}", result);
        Console.WriteLine("退出同步操作!");
    }

    // 模拟耗时操作(同步方法)
    private static int SyancWork(int val)
    {
        for (int i = 0; i < 5; ++i)
        {
            Console.WriteLine("耗时操作{0}", i);
            Thread.Sleep(100);
            val++;
        }
        return val;
    }
}

结果:

可以从右图中看到执行结果,是非常典型的同步执行方法。

async关键字能用在方法、lambda表达式的声明部分,用来标示此方法可能包含await关键字,只有拥有async才能在其内部使用await关键字。

异步方法可以具有Task、Task<>或void的返回类型;await关键字则是用于返回值是“可等待”类型(awaitable)的方法或lambda表达式内,“awaitable”可以是任何类型(常见的有Task、Task<>),它必须公开一个GetAwaiter() 方法并且返回有效的”awaiter”。

更详细的信息可以参考“关于Async与Await的FAQ”,里面介绍了这些概念与注意事项。

当一个async方法,且内部包含await关键字,它就会在编译的时候成为一个异步方法,如果没有await关键字,则它将只会被当成一个同步方法来执行。

如果对其内部实现感兴趣可以参考“异步性能:了解 Async 和 Await 的成本”一文,相信对深入了解这种机制还是有所帮助的。

现在我们尝试使用新出的异步关键字async、await来改造成异步调用:

public class Program
{
    static void Main(string[] args)
    {
        // 异步方式
        Console.WriteLine("异步方式测试开始!");
        AsyncMethod(0);
        Console.WriteLine("异步方式结束!");
        Console.ReadKey();
    }

    // 异步操作
    private static async void AsyncMethod(int input)
    {
        Console.WriteLine("进入异步操作!");
        var result = await AsyncWork(input);
        Console.WriteLine("最终结果{0}", result);
        Console.WriteLine("退出异步操作!");
    }

    // 模拟耗时操作(异步方法)
    private static async Task<int> AsyncWork(int val)
    {
        for (int i = 0; i < 5; ++i)
        {
            Console.WriteLine("耗时操作{0}", i);
            await Task.Delay(100);
            val++;
        }
        return val;
    }
}

结果:

 

 先来看结果吧,我们发现耗时操作已经是异步进行了。

整体流程大概是先由Main函数异步调用AsyncMethod,并不等待AsyncMethod完成,继续往下执行。

而AsyncMethod方式在被调用后,在分配到时间片时开始启动,执行函数体内容,并由于await AsyncWork语句而继续异步调用AsyncWork,但由于await关键字,将在此等待AsyncWork完成后,再继续往下执行。

那么,AyncWork也一样的,被调用后,在分配到时间片时开始启动,执行耗时操作。

可以看到,使用了新的关键字后,同步与异步编程的语法差别进一步减少。

随着.NET 4.5的推出,许多新类库和既有类库都支持这种新型的异步语法(比如HttpClient、HttpServer、MemoryStream...),它们以类似ReadAsync、WriteAsync、SendAsync等分开方法来提供具有async声明,且返回类型为Task、Task<>的异步工作方式。

补充:

刚才有朋友提到await Task.Delay(100)这条语句,这是为了让AsyncWork成为异步方法才加的,如果你要进行的操作不支持await修饰怎么办,其实很简单,使用Task.Factory.StartNew()就行了,举例:

// 异步操作
private static async void AsyncMethod(int input)
{
    Console.WriteLine("进入异步操作!");
    var result = await Task.Factory.StartNew((Func<object, int>)SyncWork2, input);
    Console.WriteLine("最终结果{0}", result);
    Console.WriteLine("退出异步操作!");
}

// 模拟耗时操作(同步方法)
private static int SyncWork2(object input)
{
    int val = (int)input;
    for (int i = 0; i < 5; ++i)
    {
        Console.WriteLine("耗时操作{0}", i);
        Thread.Sleep(100);
        val++;
    }
    return val;
}

这样,我们的SyncWork2实际上却是异步执行的,所得结果与前面的异步方法一致,只是这样一来输入参数只能是object类型,需要进行类型转化。

另外,除了StartNew,我们还可以新建一个Task,然后调用Run,以完成同样效果。

目前来说,这种异步工作还是会造成本人使用上的不适,不过如果在将来的版本中,继续推广使用,相信不久便能熟练,且加快写代码的速度,编写出逻辑清晰的代码。

转载请注明原址:http://www.cnblogs.com/lekko/archive/2013/03/05/2944282.html 

可以用以下代码进行async和await关键字的理解:

public class Program
{
    static void Main(string[] args)
    {
        // 异步方式
        Console.WriteLine(" 异步方式测试开始!");
        AsyncMethod(0);
        Console.WriteLine("异步方式结束!");
        Console.ReadKey();
    }

    // 异步操作
    private static async void AsyncMethod(int input)
    {
        Console.WriteLine("进入异步操作!");
        var result = await AsyncWork(input);
        //var result = AsyncWork(input);
        Console.WriteLine("最终结果{0}", result);
        Console.WriteLine("退出异步操作!");

        //await Fun2();

        for (int i = 0; i < 5; ++i)
        {
            Console.WriteLine("异步操作中 -- {0}", i);
            await Task.Delay(200);
            //Task.Delay(100);
            //System.Threading.Thread.Sleep(500);
        }
    }

    // 模拟耗时操作(异步方法)
    private static async Task<int> AsyncWork(int val)
    {
        for (int i = 0; i < 5; ++i)
        {
            Console.WriteLine("耗时操作前 - {0}", i);
            System.Threading.Thread.Sleep(500);
            val++;
        }

        for (int i = 0; i < 5; ++i)
        {
            Console.WriteLine("耗时操作{0}", i);
            await Task.Delay(500);
            //Task.Delay(100);
            //System.Threading.Thread.Sleep(500);
            val++;
        }
        return val;
    }

    private static async Task Fun2()
    {
        Console.WriteLine("Fun2 Start ...");
        for (int i = 0; i < 10; i++)
        {
            Console.WriteLine(i);
            await Task.Delay(500);
            //Task.Delay(500);
        }
        Console.WriteLine("Fun2 End ...");
    }
}

此代码可以证明,

1. 只声明了async,方法体中没有await的方法,执行时并不是异步执行,它还是同步方法并同步执行。

要想方法是异步方法,必须async和await联合使用。只有声明了async的方法在执行时碰到了await关键字时才会异步执行,即此时会异步执行该异步方法调用代码后面的代码,如果方法体内没有await关键字,则该方法还是同步方法,即同步执行。

2. 异步方法如果有返回值,则需要Task<Type>,Type为放回类型,如返回类型为int,则为Task<int>。

如果该异步方法没有返回值,则使用void或Task, void只用在某个事件函数中调用异步方法时,其他使用异步方法的情况最好都用Task, 比如Main函数中要调用一个异步方法,且该方法没有返回值,则该异步方法需要用void, 而在此异步方法中调用了另一个异步方法2,且该异步方法2也没有返回值,则该异步方法2应该用Task.

 

标签:异步,Task,Console,await,WriteLine,async
From: https://www.cnblogs.com/zhu4c4/p/16976110.html

相关文章

  • @Async实现异步任务
    1、@Async是SpringBoot自带的一个执行步任务注解@EnableAsync//开启异步@SpringBootApplicationpublicclassApplication{publicstaticvoidmain(String[]a......
  • C# Task和async/await详解
    原文链接:https://blog.csdn.net/btfireknight/article/details/97766193一、什么是异步当一个方法被调用时,调用者需要等待该方法执行完毕并返回才能继续执行,我们称这个方......
  • java8 CompletableFuture异步调用与lamda结合
    前言:jdk1.8 lamda记录异步执行动作staticvoidthenApplyAsyncExample(){CompletableFuture<String>cf=CompletableFuture.completedFuture("message").thenApplyAs......
  • Awaitility同步异步工具介绍与RocketMQ中实战
    在编写测试用例的时候遇到有异步或者队列处理的时候经常会用到 ​​Thread.sleep()​​ 等待来进行测试。例如:​​DLedger​​ 测试选举的过程。当DLedgerLeader下线。......
  • python高性能异步爬虫
    目的:在爬虫中使用异步实现高性能的数据爬取操作。异步爬虫的方式:1、多线程,多进程(不建议):好处:可以为相关阻塞的操作单独开启线程,阻塞操作就可以异步执行。弊端:无法无限制的开......
  • 异步批处理教程
    书接上回大数据量、高并发业务怎么优化?(一)文章中介绍了异步批处理的三种方式,本文继续深入针对前两种进行讲解,并给出代码示例:一普通版本,采用阻塞队列 ArrayBlockingQue......
  • script 标签中的defer 和 async 属性
    浏览器在解析HTML的时候,如果遇到一个没有任何属性的 <script>标签 ,就会暂停解析,先发送网络请求获取该JS脚本的代码内容,然后让JS引擎执行该代码,当代码执行完毕后恢......
  • 【工具】简陋的异步转同步队列
    前言最近碰到一个场景,在开发一个需求的过程中将系统的接口封装了一层,但是系统接口全部是以异步的形式回调的,这导致两个问题:外部操作传入封装类的时候,上一次的操作还未完......
  • [转]React hooks useEffect中如何使用异步函数(即如何使用async/await)
    1.useEffect的回调参数返回的是一个清除副作用的clean-up函数。因此无法返回Promise,更无法使用async/await2.如何让useEffect支持async/await2.1、方法一(推荐):useEf......
  • js中如何顺序执行异步任务
    在js中,任务可分为两种,同步任务和异步任务。(1)同步任务又叫非耗时任务,指的是在主线程排队执行的那些任务只有前一个任务执行完毕,才能执行后一个任务(2)异步任务又......