• 博客园首发自定义awaiter


    假设阅读本文的您已经对await/async有了一定了解。

    .net中的新关键字await出来很久,刚接触时心里对它非常抵触,习惯了用过去的异步模型,感觉已经足够我实现各种想要的功能,认为新出的await简化了代码,必然牺牲代码的灵活性。这段时间公司项目不忙,周围同事一起讨论await用法,讨论之间发现大家对其理解各不相同,这……激发我对await的深入研究的兴趣。

    首先说几点常见的误区,随后介绍下await的高级用法。

    误区一:带有async/await关键字的方法难道就是异步方法了吗?

    答案是:不是,有async关键字只是告诉编译器我这个方法可以用await。实际上没发起任何异步操作,

    即使再有await也不是用来发起异步操作的。await仅仅是一个高级的handler。

    误区二: 我们通常只用await后跟一个方法例如:

          await SomeMethod();

       await不是用来调用方法的前缀。它是用来接收一个异步的返回值例如Task;

    可以这样写:

    var result=SomeMethod();

    await result;

    误区三:await的控制流:微软做了大量的努力通过await/async关键字,把之前的前后颠倒,跳来跳去的控制流串成我们代码所写的顺序,

    为了增强阅读性,让我们易于调试和开发。很多人(包括之前的我)真的以为带有async的函数就是一个线程的顺序执行的控制流。

    实际上不是那样。副一张图介绍下。

    实线箭头为主线程的控制流,虚线箭头为接收异步回调开启的新线程的控制流。再看一个例子。

    现在我们避免了上面的误区可以更自由的发挥了。

    最后一个介绍才是本文的重头戏:

    await的高级应用,自定义awaiter。让我们的await可以await一切。

    之前我们的await只能这样用的:

    await SomeMethod();

    await Task.delay(5000);

    或者

    var result=SomeMethod();

    await result;

    大家有没有这样用过?

    await 5000;//延迟5秒;等于awaitTask.delay(5000);

    string s=await "http://www.hanselman.com/blog/NuGetPackageOfTheWeek13PortableHttpClientMakesPortableLibrariesMoreUseful.aspx";//get这个地址的html;

    甚至可以这样

    Task.Run(()=>{

    string s="hello";

    this.SomeTextBlock.Text=s;

    });

    上面的写法肯定是会报错的,因为不能从其他线程给UI线程的控件赋值。

    我自己封装了一个线程同步的方法:

    Task.Run(()=>{

    string s="hello";

    await this.SomeTextBlock;

    this.SomeTextBlock.Text=s;

    });

    await一下这个想要被操作的控件就可以赋值了。

     是不是很过瘾?

    我来一步一步告诉大家怎么样实现。

    await接收的是TaskAwaiter 或TaskAwaiter <T> 的返回值 所以我们定义一个扩展方法可以让await当做自定义类型的前缀。

     public static class AwaitHelper
        {
            //public static TaskAwaiter GetAwaiter(this TimeSpan timeSpan)
            //{
    
            //    return TaskEx.Delay(timeSpan).GetAwaiter();
            //}
            public static TaskAwaiter GetAwaiter(this int ms)
            {
                return Task.Delay(ms).GetAwaiter();
            }
    
            public static TaskAwaiter GetAwaiter(this string s)
            {
                return new Task(() => { }).GetAwaiter();
            }
    
            public static AllanControlAwaiter GetAwaiter(this DependencyObject control)
            {
                return new AllanControlAwaiter(control);
            }
        }

    看到这里我们就知道

    await 5000;//延迟5秒;

    是怎么实现的吧。

    下面我们继续封装一个AllanControlAwaiter实现线程同步操作

     public class AllanControlAwaiter : INotifyCompletion
        {
            private readonly DependencyObject m_control;
            private bool _IsCompleted = false;
            public AllanControlAwaiter(DependencyObject control)
            {
                m_control = control;
            }
    
            public bool IsCompleted
            {
                get { return _IsCompleted; }
            }
    
            public void OnCompleted(Action continuation)
            {
                var result = m_control.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => continuation());
                result.AsTask().Wait();
                _IsCompleted = true;
            }
    
            public void GetResult() { }
    
    
        }

    到这里大功告成。

    快去体验一下可以await一切的感觉吧!

  • 相关阅读:
    [置顶] 大型网站技术架构(六)网站的伸缩性架构
    [置顶] 大型网站技术架构(五)网站高可用架构
    [置顶] 大型网站技术架构(五)网站高可用架构
    [置顶] 大型网站技术架构(四)网站的高性能架构
    [置顶] 大型网站技术架构(四)网站的高性能架构
    [置顶] 大型网站技术架构(三)架构核心要素
    [置顶] 大型网站技术架构(二)架构模式
    [置顶] 大型网站技术架构(二)架构模式
    [置顶] 大型网站技术架构(一)大型网站架构演化
    [置顶] 大型网站技术架构(一)大型网站架构演化
  • 原文地址:https://www.cnblogs.com/allanxyq/p/2975431.html
Copyright © 2020-2023  润新知