• APM异步编程模型的优势


    我们之所以要花大力气学习APM,就必须要清楚它能解决实际编程中的那些难题。以及现有的技术为什么不行。

    简单点说:APM是基于IAsyncResult接口的,采用的BeginXXX和EndXXX的形式来实现异步。

    下面这几点就是APM的优势:

    1,线程执行是异步的,不会阻塞调用线程。这一点也是我们使用异步的主要目的,我们不就是希望后台处理一些耗时操作吗?

    2,任务完成可以得到通知。(非阻塞)

    3,任务可以实现进度报告。(需要额外的辅助代码支持)

    4,可以有返回值。

    5,参数可以是多个。

    再看看Thread,ThreadPool,Task能实现上面的几点?这三个中,Task是相对完善的一个,对于第2点它可以通过ContineWith方法来实现,对于第5点,它可以通过Lamda表达式的参数捕获来实现。但总觉得有点怪怪的,没有APM灵活。而对于Thread,ThreadPool来说,除了第1点,其它的都不行。

    1,FCL中提供了大量现成的,基于I/O的异步操作实现类。

    如,Stream,WebRequest,Dns,SqlCommand等等。对于开发者来说,直接使用它们就可以了。

                WebRequest webRequest = WebRequest.Create("http://www.baidu.com");
                webRequest.BeginGetResponse(result =>
                {
                    WebResponse webResponse = null;
                    try
                    {
                        webResponse = webRequest.EndGetResponse(result);
                        using (System.IO.FileStream fs = new System.IO.FileStream("D:baidu.html", System.IO.FileMode.Create, System.IO.FileAccess.Write))
                        {
                            using (System.IO.Stream webStream = webResponse.GetResponseStream())
                            {
                                webStream.CopyTo(fs);
                            }
                        }
                    }
                    catch (WebException ex)
                    {
                        Console.WriteLine("Failed:" + ex.GetBaseException().Message);
                    }
                    finally
                    {
                        if (webResponse != null) webResponse.Close();
                    }
                }, null);

    2,将IAsyncResutl转成Task来完成。也是上面的代码的不同版本。

    这里就是用TaskFactroy的FromAsync方法将IAsyncResutl转成了Task,你肯定觉得这是多余的,但是Task的优势在于它可以有后续Task,可以按顺序执行,在某些场合,这个功能是非常有用的。

                WebRequest webRequest = WebRequest.Create("http://www.baidu.com");
                TaskFactory factroy = new TaskFactory();
                Task<WebResponse> task = factroy.FromAsync<WebResponse>(webRequest.BeginGetResponse, webRequest.EndGetResponse, TaskCreationOptions.None);
                task.ContinueWith(t => {
                    WebResponse webResponse = null;
                    try
                    {
                        webResponse = t.Result;
                        using (System.IO.FileStream fs = new System.IO.FileStream("D:baidu.html", System.IO.FileMode.Create, System.IO.FileAccess.Write))
                        {
                            using (System.IO.Stream webStream = webResponse.GetResponseStream())
                            {
                                webStream.CopyTo(fs);
                            }
                        }
                    }
                    catch (WebException ex)
                    {
                        Console.WriteLine("Failed:" + ex.GetBaseException().Message);
                    }
                    finally
                    {
                        if (webResponse != null) webResponse.Close();
                    }
                
                });

    3,用代理类型(delegate)实现异步调用。

    上面的代码都是在调用.Net类库实现的APM类。难道我们有个方法需要异步执行,也需要去包装,实现BeginXXX和EndXXX以及相关的接口吗?如果是这样,如此复杂的APM谁还会用。幸好,代理Delegate天生就支持APM模型。我们申明了一个delegate后,编译器就会自动为我们生成BeginInvoke和EndInvoke等方法。于是乎,我们要做的工作就简单多了,声明一个和方法签名一致的带类类型。调用它的BgeinInvoke方法和EndInvoke方法。就是这么简单!

            //假设:这是我们想要异步执行的方法,它有三个参数,和一个自定义类型的返回值
            private UserInfo OurFunction(string param1, string param2, string param3)
            {
                //...
                //...
                UserInfo uInfo = new UserInfo();
                return uInfo;
            }
            //第一步:定义一个和它签名一致的代理类型
            private delegate UserInfo OurFunctionDelegate(string param1, string param2, string param3);
    
    private void MainFunction() { //第二步:声明这个代理类型
    OurFunctionDelegate hander = new OurFunctionDelegate(OurFunction); //第三步:调用BgeinInvoke方法,同时传入一个回调函数 hander.BeginInvoke("p1", "p2", "p3", AsyncCallBack, hander); } //第四步:定义一个回调函数 private void AsyncCallBack(IAsyncResult result) { OurFunctionDelegate hander = (OurFunctionDelegate)result.AsyncState; try { //函数异步执行完成,会进入这个函数,调用EndInvoke方法可以得到结果,如有异常,也会在这里抛出 UserInfo info = hander.EndInvoke(result); } catch (Exception) { //处理异步操作的异常,当然,这里的异常应该是ArrgregateException。 } }

    注意事项:对于异步调用获取结果的方式,主要有以下几种。

    1,利用AsyncCallBack回调函数,它是不阻塞的。(首选)

    2,利用IAsyncResult的Result。调用线程遇到这句话会阻塞。

    3,利用IAsyncResult的AsyncWaitHandle.WaitOne()。和2一样会阻塞。

    4,轮询IAsyncResult的IsCompleted属性。同样会耗CPU资源,阻塞调用线程,如新开一个线程来轮询又浪费线程资源。

  • 相关阅读:
    Mac环境下svn的使用
    开发中常见问题集锦
    【C语言】07基本语句和运算
    【C语言】05printf和scanf函数
    【C语言】03第一个C程序代码分析
    【C语言】06基本数据类型
    【C语言】04函数
    【C语言】01C语言概述
    让UIWebView弹出键盘上的按钮显示中文
    【C语言】02第一个C程序
  • 原文地址:https://www.cnblogs.com/xiashengwang/p/2648883.html
Copyright © 2020-2023  润新知