zoukankan      html  css  js  c++  java
  • 【温故知新】c#异步编程模型(APM)--使用委托进行异步编程

    当我们用到C#类许多耗时的函数XXX时,总会存在同名的类似BeginXXX,EndXXX这样的函数。

    例如Stream抽象类的Read函数就有

            public abstract int Read(byte[] buffer, int offset, int count);
    
            public virtual IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state);
            
            public virtual IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state);

    这也就是所谓的APM异步编程模型,基于委托实现,其实就是启动了一个后台线程(主线程结束,则该线程结束),其中IAsyncResult就是异步状态接口,用来检测异步是否完成。

    代码模拟场景1:

    每到大热天的中午就不想动,出门就是一身汗,所以一般午餐时间我都选择定外卖,正好等外卖这段时间还可以完善一下上午的工作内容。这就相当于委托一名外卖小哥异步帮我送一份快餐过来,这段时间我继续干我的事情。

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace BeginInvoke
    {
        class Program
        {
            //声明一个送外卖的委托类型
            private delegate int DeliveryDelegate(string foodname);
    static void Main(string[] args) { Console.WriteLine("天气太热,带电话叫外卖小哥送一份番茄炒蛋"); //声明一个外卖小哥,委托他去帮我拿午餐。 DeliveryDelegate DeliveryBoy = new DeliveryDelegate(GetFood); //开始CALL电话(异步调用,由于还没用到回调函数,后两个参数填空) IAsyncResult ar = DeliveryBoy.BeginInvoke("番茄炒蛋", null, null); //继续干自己的事…… Console.WriteLine("完善上午的工作~大概5分钟完成"); Thread.Sleep(1000); Console.WriteLine("完善20%"); Thread.Sleep(1000); Console.WriteLine("完善40%"); Thread.Sleep(1000); Console.WriteLine("完善60%"); Thread.Sleep(1000); Console.WriteLine("完善80%"); Thread.Sleep(1000); Console.WriteLine("完善100%"); Console.WriteLine("完善工作完成");//但是外卖还没到 Console.WriteLine("等外卖……好饿,估计还要5分钟才到"); //此时调用EndInvoke会阻塞住线程直到异步调用完成,这时相当于我就主动蹲在门口等外卖小哥送上门,如果小哥先到,只能在门口等我办完事~。 int money = DeliveryBoy.EndInvoke(ar); Console.WriteLine("给快递小哥" + money + "元,开吃"); } /// <summary> /// 获取食物 /// </summary> /// <param name="foodname">食物名</param> /// <returns>价格</returns> private static int GetFood(string foodname) { Console.WriteLine("外卖小哥顶着烈日送餐ing,预计10分钟后到"); Thread.Sleep(10000); Console.WriteLine("外卖到达~" + foodname); //不管什么菜一律10元钱! return 10; } } }

    运行结果:

    天气太热,带电话叫外卖小哥送一份番茄炒蛋
    完善上午的工作~大概5分钟完成
    外卖小哥顶着烈日送餐ing,预计10分钟后到
    完善20%
    完善40%
    完善60%
    完善80%
    完善100%
    完善工作完成
    等外卖……好饿,估计还要5分钟才到
    外卖到达~番茄炒蛋
    给快递小哥10元,开吃

    注:如果使用ar.AsyncWaitHandle.WaitOne();可以设置指定等待时间间隔

                if (ar.AsyncWaitHandle.WaitOne())//也会阻塞住线程直到异步调用完成,EndInvoke之后会自动收到Set信号。
                {
                    int money = DeliveryBoy.EndInvoke(ar);
                    Console.WriteLine("给快递小哥" + money + "元,开吃");
                    //如果调用ar.AsyncWaitHandle.WaitOne();,记得EndInvoke后要主动Close哟!
                    ar.AsyncWaitHandle.Close();
                }

    代码模拟场景2:

    之前的场景,如果我没有做完工作,那么外卖小哥只能在门口一直等我做完事情(没办法通知我外卖到了,只有我主动去检查),这个时候回调函数就派上用处了,我就再也不用担心外卖什么时候到,因为我又委托一个人专门帮我在门口盯着外卖小哥!

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Runtime.Remoting.Messaging;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace BeginInvoke
    {
        class Program
        {
            //声明一个送外卖的委托类型
            private delegate int DeliveryDelegate(string foodname);
            static void Main(string[] args)
            {
                Console.WriteLine(DateTime.Now.ToString());
                Console.WriteLine("天气太热,带电话叫外卖小哥送一份番茄炒蛋");
    
                //声明一个外卖小哥,委托他去帮我拿午餐。
                DeliveryDelegate DeliveryBoy = new DeliveryDelegate(GetFood);
    
                //开始CALL电话(异步调用,AsyncCallback其实也是一个delegate类型,实例化delegate委托一个人专门帮我在门口盯着外卖小哥)
                IAsyncResult ar = DeliveryBoy.BeginInvoke("番茄炒蛋", new AsyncCallback(GetFoodCallback), "番茄炒蛋");
    
                //继续干自己的事……
                Console.WriteLine("完善上午的工作~大概5分钟完成");
                Thread.Sleep(1000);
                Console.WriteLine("完善20%");
                Thread.Sleep(1000);
                Console.WriteLine("完善40%");
                Thread.Sleep(1000);
                Console.WriteLine("完善60%");
                Thread.Sleep(1000);
                Console.WriteLine("完善80%");
                Thread.Sleep(1000);
                Console.WriteLine("完善100%");
                Console.WriteLine("完善工作完成");//但是外卖还没到
    
                Console.WriteLine("外卖估计还要5分钟才到,时间不等人,撸一盘");
    
                //中途外卖到了,回调函数帮我付钱拿外卖,我继续撸。
                Console.WriteLine("LOL……一局10分钟");
                for (int i = 0; i < 10; i++)
                {
                    Thread.Sleep(1000);
                    Console.WriteLine("过去了1分钟");
                }
    
                Console.WriteLine("LOL拿到了首胜!,吃饭");
    
                if (ar.IsCompleted)
                {
                    Console.WriteLine("好吃~");
                }
            }
    
            /// <summary>
            /// 获取食物
            /// </summary>
            /// <param name="foodname">食物名</param>
            /// <returns>价格</returns>
            private static int GetFood(string foodname)
            {
                Console.WriteLine("外卖小哥顶着烈日送餐ing,预计10分钟后到");
                Thread.Sleep(10000);
                Console.WriteLine("外卖到达~" + foodname);
                //不管什么菜一律10元钱!
                return 10;
            }
    
            /// <summary>
            /// 异步完成,回调(完成时执行)
            /// 回调在 ThreadPool 线程上执行。 ThreadPool 线程是后台线程,这些线程不会在主线程结束后保持应用程序的运行,因此示例的主线程必须休眠足够长的时间以便回调完成。
            /// </summary>
            /// <param name="ar">异步状态</param>
            private static void GetFoodCallback(IAsyncResult ar)
            {
                AsyncResult result = (AsyncResult)ar;
                DeliveryDelegate dd = result.AsyncDelegate as DeliveryDelegate;
                int money = dd.EndInvoke(ar);
                string foodname = ar.AsyncState as string;
                Console.WriteLine("拿外卖!" + foodname + ",一共" + money + "");
                Console.WriteLine("付钱");
            }
        }
    }

    运行结果:

    天气太热,带电话叫外卖小哥送一份番茄炒蛋
    完善上午的工作~大概5分钟完成
    外卖小哥顶着烈日送餐ing,预计10分钟后到
    完善20%
    完善40%
    完善60%
    完善80%
    完善100%
    完善工作完成
    外卖估计还要5分钟才到,时间不等人,撸一盘
    LOL……一局10分钟
    过去了1分钟
    过去了1分钟
    过去了1分钟
    过去了1分钟
    过去了1分钟
    外卖到达~番茄炒蛋
    拿外卖!番茄炒蛋,一共10元
    付钱
    过去了1分钟
    过去了1分钟
    过去了1分钟
    过去了1分钟
    过去了1分钟
    LOL拿到了首胜!,吃饭
    好吃~

    参考:

    https://msdn.microsoft.com/zh-cn/library/ms228963(v=vs.110).aspx

    https://msdn.microsoft.com/zh-cn/library/system.iasyncresult(v=vs.110).aspx

    https://msdn.microsoft.com/zh-cn/library/2e08f6yc(v=vs.110).aspx

  • 相关阅读:
    全面分析C#方法中的ref和out
    SQL注入漏洞全接触入门篇
    如何使用四个语句来提高 SQL Server 的伸缩性
    5种提高SQL性能的方法
    SQL注入漏洞全接触高级篇
    网络游戏程序员须知 收包与发包
    SQL注入攻击的原理及其防范措施
    SQL注入漏洞全接触进阶篇
    C#委托的故事
    转眼又快一年了,最近没赚钱,在学习FLASH as3编程
  • 原文地址:https://www.cnblogs.com/leestar54/p/4596675.html
Copyright © 2011-2022 走看看