C# 语法:await与async的正确打开方式

点击上方“程序员大咖”,选择“置顶公众号”

关键时刻,第一时间送达!640?640?wx_fmt=gif















































































































































































































































































































    先不说楚枫的这般年纪,能够踏入元武一重说明了什么,最主要的是,楚枫在刚刚踏入核心地带时,明明只是灵武七重,而在这两个月不到的时间,连跳两重修为,又跳过一个大境界,踏入了元武一重,这般进步速度,简直堪称变态啊。


    “这楚枫不简单,原来是一位天才,若是让他继续成长下去,绝对能成为一号人物,不过可惜,他太狂妄了,竟与龚师兄定下生死约战,一年时间,他再厉害也无法战胜龚师兄。”有人认识到楚枫的潜力后,为楚枫感到惋惜。


    “哼,何须一年,此子今日就必败,巫九与龚师兄关系甚好,早就看他不顺眼了,如今他竟敢登上生死台挑战巫九,巫九岂会放过他?”但也有人认为,楚枫今日就已是在劫难逃。


    “何人挑战老子?”就在这时,又是一声爆喝响起,而后一道身影自人群之中掠出,最后稳稳的落在了比斗台上。


    这位身材瘦弱,身高平平,长得那叫一个猥琐,金钩鼻子蛤蟆眼,嘴巴一张牙带色儿,说话臭气能传三十米,他若是当面对谁哈口气,都能让那人跪在地上狂呕不止。


    不过别看这位长得不咋地,他在核心地带可是鼎鼎有名,剑道盟创建者,青龙榜第九名,正是巫九是也。


    “你就是巫九?”楚枫眼前一亮,第一次发现,世间还有长得如此奇葩的人。


    巫九鼻孔一张,大嘴一咧,拍着那干瘪的肚子,得意洋洋的道:“老子就是巫九,你挑战老子?”


    “不是挑战你,是要宰了你。”楚枫冷声笑道。


    “好,老子满足你这个心愿,长老,拿张生死状来,老子今日在这里了解了这小子。”巫九扯开嗓子,对着下方吼了一声。


    如果他对内门长老这么说话,也就算了,但是敢这么跟核心长老说话的,他可真是算作胆肥的,就连许多核心弟子,都是倒吸了一口凉气,心想这楚枫够狂,想不到这巫九更狂。


    不过最让人无言的就是,巫九话音落下不久,真有一位核心长老自人群走出,缓缓得来到了比斗台上,左手端着笔墨,右手拿着生死状,来到了巫九的身前。


    “我去,这巫九什么身份,竟能这般使唤核心长老?”有人吃惊不已,那长老修为不低,乃是元武七重,比巫九还要高两个层次,但却这般听巫九的话,着实让人吃惊不已。


    “这你就不知道了吧,巫九在前些时日,拜了钟离长老为师尊,已正式得到钟离长老的亲传。”有人解释道。


    “钟离长老?可是那位性情古怪的钟离一护?”


    “没错,就是他。”


    “天哪,巫九竟然拜入了他的门下?”


    人们再次大吃一惊,那钟离一护在青龙宗可是赫赫有名,若要是论其个人实力,在青龙宗内绝对能够排入前三,连护宗六老单打独斗都不会是他的对手。


    只不过那钟离一护,如同诸葛青云一样,也是一位客卿长老,所以在青龙宗内只是挂个头衔,什么事都不管,更别说传授宗内弟子技艺了,如今巫九竟然能拜入他老人家门下,着实让人羡慕不已。


    “恩怨生死台,的确可以决斗生死,但必须要有所恩怨,你们两个人,可有恩怨?”那位长老开口询问道。































































































C#5.0推出了新语法,await与async,但相信大家还是很少使用它们。关于await与async有很多文章讲解,但有没有这样一种感觉,你看完后,总感觉这东西很不错,但用的时候,总是想不起来,或者不知道该怎么用。


为什么呢?我觉得大家的await与async的打开方式不正确。


正确的打开方式


首先看下使用约束。


1、await 只能在标记了async的函数内使用。


2、await 等待的函数必须标记async。


有没有感觉这是个循环?没错,这就是个循环。这也就是为什么大家不怎么用他们的原因。这个循环很讨厌,那么怎么破除这个循环呢?


【很简单,await等待的是线程,不是函数。】


不理解吗?没关系,接着看下去。


下面从头来讲解,首先看这么一组对比


public static int NoAsyncTest()

{

   return 1;

}

public static async Task<int> AsyncTest()

{

  return 1;

}


async Task<int>等于int


这意味着我们在正常调用这两个函数时,他们是等效的。那么用async Task<int>来修饰int目的是什么呢?


目的是为了让这个方法这样被调用 await AsyncTest(),但直接这样调用,并不会开启线程,那这样费劲的修饰是不是就没什么意义了呢。


当然不是,那什么时候会让 await AsyncTest()有意义呢?


我们接着往下看,修改AsyncTest如下。然后,此时再调用await AsyncTest(),你会神奇的发现,依然没有卵用。。。


Excute方法正常执行,而AsyncTest内运行的线程,自己执行自己的。


public static async void Excute()

{

      Console.WriteLine(Thread.CurrentThread.GetHashCode() + " 开始 Excute " + DateTime.Now);

      await AsyncTest();

      Console.WriteLine(Thread.CurrentThread.GetHashCode() + " 结束 Excute " + DateTime.Now);

}

public static async Task<int> AsyncTest()

{

       Task.Run(() =>

           {

               Console.WriteLine(Thread.CurrentThread.GetHashCode() + " Run1 " + DateTime.Now);

               Thread.Sleep(1000);

           });

           return 1;

}


640?wx_fmt=png


别着急,我们稍作调整,在线程后面增加.GetAwaiter().GetResult()。这句话是干什么用的呢?是用来获取线程返回值的。


这个逻辑是这样的,如果想要获取线程返回结果,就自然要等待线程结束。


运行一下,我们将看下面的结果。


public static async Task<int> AsyncTest()

{

    Task.Run(() =>

    {

        Console.WriteLine(Thread.CurrentThread.GetHashCode() + " Run1 " + DateTime.Now);

        Thread.Sleep(1000);

    }).GetAwaiter().GetResult();

    return 1;

}


640?wx_fmt=png


但是,好像await AsyncTest();还是没启作用。没错,事实就是,他真的不会起作用。。。


那么怎么才能让他起作用呢?


首先,我们定义一个普通函数,他的返回值是一个Task,然后我们得到Task后,运行它,再用await等待这个Task。


于是我们就得到这样的结果。


public static async void Excute()

{

    Console.WriteLine(Thread.CurrentThread.GetHashCode() + " 开始 Excute " + DateTime.Now);

    var waitTask = AsyncTestRun();

    waitTask.Start();

    int i = await waitTask;

    Console.WriteLine(Thread.CurrentThread.GetHashCode() + " i " + i);

    Console.WriteLine(Thread.CurrentThread.GetHashCode() + " 结束 Excute " + DateTime.Now);

}

public static Task<int> AsyncTestRun()

{

    Task<int> t = new Task<int>(() => {

        Console.WriteLine(Thread.CurrentThread.GetHashCode() + " Run1 " + DateTime.Now);

        Thread.Sleep(1000);

        return 100;

    });

    return t;

}


640?wx_fmt=png


如图,这样写await AsyncTest();就起作用了。


所以,还是那句话,await等待的是线程,不是函数。


但在图里,我们发现很奇怪的一点,结束Excute也是线程3,而不是线程1。也就是说,Await会对线程进行优化。


下面看下两组代码的对比,让我们就更清楚的了解下Await。


第一组,使用await等待线程。


public static async void Excute()

{

   Console.WriteLine(Thread.CurrentThread.GetHashCode() + " 开始 Excute " + DateTime.Now);

   await SingleAwait();

   Console.WriteLine(Thread.CurrentThread.GetHashCode() + " 结束 Excute " + DateTime.Now);

}

       

public static async Task SingleAwait()

{

     Console.WriteLine(Thread.CurrentThread.GetHashCode() + " AwaitTest开始 " + DateTime.Now);

     await Task.Run(() =>

            {

                Console.WriteLine(Thread.CurrentThread.GetHashCode() + " Run1 " + DateTime.Now);

                Thread.Sleep(1000);

            });

            await Task.Run(() =>

            {

                Console.WriteLine(Thread.CurrentThread.GetHashCode() + " Run2 " + DateTime.Now);

                Thread.Sleep(1000);

            });

            Console.WriteLine(Thread.CurrentThread.GetHashCode() + " AwaitTest结束 " + DateTime.Now);

            return;

}


640?wx_fmt=png


第二组,使用等待线程结果,等待线程。


public static async void Excute()

{

     Console.WriteLine(Thread.CurrentThread.GetHashCode() + " 开始 Excute " + DateTime.Now);

            await SingleNoAwait();

     Console.WriteLine(Thread.CurrentThread.GetHashCode() + " 结束 Excute " + DateTime.Now);

        }

public static async Task SingleNoAwait()

{

      Console.WriteLine(Thread.CurrentThread.GetHashCode() + " SingleNoAwait开始 " + DateTime.Now);

       Task.Run(() =>

        {

                Console.WriteLine(Thread.CurrentThread.GetHashCode() + " Run1 " + DateTime.Now);

                Thread.Sleep(1000);

            }).GetAwaiter().GetResult();

            Task.Run(() =>

            {

                Console.WriteLine(Thread.CurrentThread.GetHashCode() + " Run2 " + DateTime.Now);

                Thread.Sleep(1000);

            }).GetAwaiter().GetResult();

            Console.WriteLine(Thread.CurrentThread.GetHashCode() + " SingleNoAwait结束 " + DateTime.Now);

            return;

}


640?wx_fmt=png


可以明确的看到,第二组,线程重新回到了主线程1中,而第一组,已经被优化到了线程4中。


结语


await是一种很便捷的语法,他的确会让代码简洁一些,但他主动优化线程的功能,如果不了解就使用,可能会导致一些奇怪的BUG发生。


这也是官方为什么只提供了await调用服务的例子,因为,在程序内调用,await还是要了解后,再使用,才安全。


640.jpeg

  • 来源:kiba518

  • cnblogs.com/kiba/p/9292904.html

  • 程序员大咖整理发布,转载请联系作者获得授权

640?wx_fmt=gif640?【点击成为源码大神】

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Resource Page Description 在以前的文章中,我曾多次强调应用程序中异步化的重要性。尤其对于IO密集型操作,异步执行对于应用程序的响应能力和伸缩性有非常关键的影响。正确使用异步编程能够使用尽可能少的线程来执行大量的IO密集型操作。可惜的是,即时异步编程有避免线程阻塞等诸多好处,但是这种编程方式至今没有被大量采用。其原因有很多,其中最主要的一点可能就是异步模型在编程较为困难,导致许多开发人员不愿意去做。 异步,则意味着一个任务至少要被拆分为“二段式”的调用方式:一个方法用于发起异步请求,另一个方法用于异步任务完成后的回调。与传统方法调用方式相比,异步调用时的中间数据不能存放在线程栈上,方法之间的也不能简单地通过参数传递的方式来共享数据。此外,传统方法调用中的try…catch…finally,using等关键字都无法跨越方法边界,因此异步编程在处理异常,保护资源等方面也需要花更大的精力才行。如果一不小心,轻则造成资源泄露,重则使整个应用程序崩溃。 因此,无论是微软官方还是社区中都出现了一些简化异步编程方式的组件,例如微软并行与协调运行时和Wintellect's .NET Power Threading Library中的AsyncEnumerator。同时,我基于AsyncEnumerator构建了一个AsyncTaskDispatcher组件,使多个有依赖关系的异步操作之间的协作调用得以大大简化。 以上是引用,自己做了个更简单的demo
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值