.Net异步编程模式

异步编程模式的英文全称是The Asynchronous Programming Models,简称是APM。简单说明一下为什么要异步编程,以及异步编程带来的好处有:

1. 快速响应的用户界面

对于用户界面而言,它的响应用户的能力是非常关键的。如果耗时的操作阻塞了UI线程,造成UI线程不能响应用户操作。用户就会抛弃我们的系统。所以我们需要一种机制,在发起耗时操作的请求之后要立即返回,不要阻塞UI线程,让UI线程可以继续响应用用户的操作。然后等耗时操作返回后,通过回调来处理耗时操作返回的结果。

2. 更高的伸缩性

在服务端应用中,有非常多的IO操作:数据库访问,磁盘操作,Socket访问等。对于这些IO操作,单独占用一个线程来同步处理,浪费服务器的资源,使用IOCP异步方式可以有效解决这种问题,关于IOCP的具体信息,可以阅读本订阅号之前的文章。

所以我们需要掌握异步编程的技能。在.Net Framework中,可以实现异步编程的方式有很多种,今天我们主要分析四种异步的方式:

1. The Standard APM

2. The Event-based APM

3. The Task-based APM

4. The Await Async APM

一、The Standard APM

在FCL提供了具有BeginXxx和EndXxx方法的各种类型,一般这种命名的方法,就提供了Standard APM的支持。通常BeginXxx方法具有Xxx方法相同的参数以外,还有两个附加参数:callback和stateObject。callback就是异步的回调方法,它需要接受一个IAsyncResult类型的参数,然后在回调方法中访问它的AsyncState属性就可以得到stateObject的值。示例代码:

class StandardAPM
{
    public static void Test()
    {
        Console.WriteLine("1. Begin");
        WebRequest request = HttpWebRequest.Create("http://www.baidu.com");
        request.BeginGetResponse(DoCallback, request);
        Console.WriteLine("2. Sync continue");
    }

    static void DoCallback(IAsyncResult ar)
    {
        WebRequest request = (WebRequest)ar.AsyncState;
        WebResponse response = request.EndGetResponse(ar);
        request.Abort();
        response.Close();
        Console.WriteLine("3. Async callback");
    }
}

通过使用Standard APM,您的代码变得更加复杂,代码逻辑不清楚。

二、The Event-based APM

框架类库(FCL)还附带了一些支持基于事件的APM的类型。例如,在使用System.Net.WebClient类的时候,通过调用DownloadDataAsync方法,并且把回调方法订阅在DownloadDataCompleted事件上,可以帮助我们达到异步效果。程序开始异步操作从指定的URL下载数据,当它完成时,将触发DownloadDataCompleted事件。示例代码:

class EventBasedAPM
{
    public static void Test()
    {
        WebClient wc = new WebClient();
        wc.DownloadDataCompleted += DoCompleted;

        Console.WriteLine("1. Begin");
        wc.DownloadDataAsync(new Uri("https://www.baidu.com"));
        Console.WriteLine("2. Sync continue");
    }

    public static void DoCompleted(object sender
        , DownloadDataCompletedEventArgs e)
    {
        Console.WriteLine("3. Async callback");
    }
}

实际上它的作用与使用BeginXxx和EndXxx方法相同,区别在于基于事件的APM更接近对象模型层,但是FCL支持基于事件APM的类型非常少,个人建议尽可能不要使用这种模式。

三、The Task-based APM

.NETFramework4.0引入了用于并行计算和异步编程的新任务并行库(TPL)。在System.Threading.Tasks命名空间中定义的主要使用的Task类表示要完成的用户工作项,要使用基于任务的APM,您必须创建Task的新实例,或者Task<T>类,传递Action或Action<T>委托的实例作为Task或Task<T>构造函数的第一个参数,然后调用Task的实例方法Start,通知任务调度程序尽快安排此任务。示例代码:

class TaskBasedAPM
{
    public static void Test()
    {
        Console.WriteLine("1. Begin");
        DoAsync();
        Console.WriteLine("2. Sync continue");
    }

    static void DoAsync()
    {
        WebRequest request = HttpWebRequest.Create("http://www.baidu.com");
        Task<WebResponse> task = request.GetResponseAsync();
        task.ContinueWith(t => {
            request.Abort();
            t.Result.Close();
            Console.WriteLine("3. Async callback");
        });
    }
}

四、The Await Async APM

在C# 5.0中引入了async和await关键字,它们是异步编码的语法糖,在C#编译器进行编译之后,能够达到异步的效果,写出来的代码更加接近同步代码,逻辑更加清楚,易于阅读。它的异步原理是和Task-based APM一样的。示例代码:

class AwaitAsyncAPM
{
    public static void Test()
    {
        Console.WriteLine("1. Begin");
        DoAsync();
        Console.WriteLine("2. Sync continue");
    }

    static async Task DoAsync()
    {
        WebRequest request = HttpWebRequest.Create("http://www.baidu.com");
        WebResponse webResponse = await request.GetResponseAsync();
        request.Abort();
        webResponse.Close();
        Console.WriteLine("3. Async callback");
        //使用await和async关键字定义的异步方法,可以return返回值也可以没有。
        //有没有return语句的时候,异步方法返回的是Task
        //有return语句的时候,异步方法返回的是Task<ResultType>
        //当调用返回的task.Result的时候,线程会阻塞,并等待异步方法真实返回结果。
    }
}

最后在这四种方式进行总结:

The Standard APM: 是基于线程池实现的,可以广泛使用,标准,推荐,支持取消和延续。

The Event-based APM: 是基于线程池实现的,尽量避免使用,不建议使用。

The Task-based APM: 是指定的任务调度程序,推荐,支持线程池模式的所有功能,并具有许多其他功能。

The Await Async APM: 是基于Task-based APM的模式,新的C#5.0异步模式,推荐使用。

原文发布于微信公众号 - 明丰随笔(liumingfengwx2)

原文发表时间:2019-05-28

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券