• .net利用委托BeginInvoke和EndInvoke实现异步编程


    最近看书,看到了可以利用学过的委托知识实现异步编程,这里做一个简单的说明示例。如果委托对象在调用列表中只有一个方法(引用方法),他就可有异步执行这个方法。委托类有两个方法,BeginInvoke和EndInvoke。

    • 当我们调用委托的BeginInvoke方法时,它开始在一个独立线程上执行引用方法。并且立即返回到原始线程。原始线程可以继续。而引用方法会在线程池中的线程中并行执行。
    • 当程序希望获取已完成的异步方法的结果时,可以检查BeginInvoke返回的IAsyncResult的IsCompleted属性。或调用委托的EndInvoke方法来等待委托完成。

    等待-直到完成 模式

            delegate string MyDownLoadDel(string weburl);
            static void Main(string[] args)
            {
                Stopwatch watch = new Stopwatch();
                watch.Start();
                Debug.WriteLine(string.Format("开始计时:{0,4:N0}ms", watch.Elapsed.TotalMilliseconds));
                MyDownLoadDel del = new MyDownLoadDel(DownLoadWeb);
                IAsyncResult iar = del.BeginInvoke("https://www.asp.net/", null, null);
                Debug.WriteLine(string.Format("委托BeginInvoke:{0,4:N0}ms", watch.Elapsed.TotalMilliseconds));
                string str = del.EndInvoke(iar);
                Debug.WriteLine(string.Format("EndInvoke,下载网站大小:{0}耗时:{1,4:N0}ms", str.Length, watch.Elapsed.TotalMilliseconds));
                Console.ReadKey(); //暂停
            }
            public static string DownLoadWeb(string url)
            {
                WebClient wc = new WebClient();
                string str = wc.DownloadString(url);
                Debug.WriteLine(string.Format("下载网站{0}结束", url));
                return str;
            }

    返回的结果为:

    开始计时:   0ms
    委托BeginInvoke:  33ms
    下载网站https://www.asp.net/结束
    EndInvoke,下载网站大小:30543耗时:1,025ms

    轮询模式

            delegate string MyDownLoadDel(string weburl);
            static void Main(string[] args)
            {
                Stopwatch watch = new Stopwatch();
                watch.Start();
                Debug.WriteLine(string.Format("开始计时:{0,4:N0}ms", watch.Elapsed.TotalMilliseconds));
                MyDownLoadDel del = new MyDownLoadDel(DownLoadWeb);
                IAsyncResult iar = del.BeginInvoke("https://www.asp.net/", null, null);
                Debug.WriteLine(string.Format("委托BeginInvoke:{0,4:N0}ms", watch.Elapsed.TotalMilliseconds));
                while (!iar.IsCompleted)
                {
                    Debug.WriteLine(string.Format("还没有完成:{0,4:N0}ms", watch.Elapsed.TotalMilliseconds));
                    Thread.Sleep(1000);
                }
                string str = del.EndInvoke(iar);
                Debug.WriteLine(string.Format("EndInvoke,下载网站大小:{0}耗时:{1,4:N0}ms", str.Length, watch.Elapsed.TotalMilliseconds));
                Console.ReadKey(); //暂停
            }
            public static string DownLoadWeb(string url)
            {
                WebClient wc = new WebClient();
                string str = wc.DownloadString(url);
                Debug.WriteLine(string.Format("下载网站{0}结束", url));
                return str;
            }

    返回结果为:

    开始计时:   0ms
    委托BeginInvoke:  29ms
    还没有完成:  29ms
    还没有完成:1,052ms
    还没有完成:2,059ms
    还没有完成:3,066ms
    还没有完成:4,078ms
    下载网站https://www.asp.net/结束
    EndInvoke,下载网站大小:30561耗时:5,084ms

    回调模式:

    回调模式和前面的不同之处在于,一旦初始线程发起了异步方法,它就自己管自己,不在考虑同步。当异步方法调用结束之后,系统调用一个用户自定义的方法来处理结果。并且返回委托的EndInvoke方法。这个用户自定义方法称为回调或者回调函数。

    BeginInvoke的参数列表中最后两个额外的参数由回调函数使用。

    • 第一个参数callback,是回调方法的名字。
    • 第二个参数state,可以是null或传入回调方法的一个对象的引用。我们可以通过使用IAsyncResult参数的AsyncState属性来获取这个对象,参数的类型是object。
            delegate string MyDownLoadDel(string weburl);
            static void Main(string[] args)
            {
                Stopwatch watch = new Stopwatch();
                watch.Start();
                Debug.WriteLine(string.Format("开始计时:{0,4:N0}ms", watch.Elapsed.TotalMilliseconds));
                MyDownLoadDel del = new MyDownLoadDel(DownLoadWeb);
                IAsyncResult iar = del.BeginInvoke("https://www.asp.net/", new AsyncCallback(CallWhenDone), null);
                //new AsyncCallback 表示异步操作完成调用,如果直接写CallWhenDone,那么程序运行是同步完成
                Debug.WriteLine(string.Format("委托BeginInvoke:{0,4:N0}ms", watch.Elapsed.TotalMilliseconds));
                Thread.Sleep(1000);
                Debug.WriteLine(string.Format("主线程运行耗时:{0,4:N0}ms", watch.Elapsed.TotalMilliseconds));
                Console.ReadKey(); //暂停
            }
            public static string DownLoadWeb(string url)
            {
                WebClient wc = new WebClient();
                string str = wc.DownloadString(url);
                Debug.WriteLine(string.Format("下载网站{0}结束", url));
                return str;
            }
            public static void CallWhenDone(IAsyncResult iar)
            {
                Debug.WriteLine(string.Format("进入回调方法体"));
                AsyncResult ar = (AsyncResult)iar; //获取类对象的引用
                MyDownLoadDel del = (MyDownLoadDel)ar.AsyncDelegate; //获取委托的引用
                string str = del.EndInvoke(iar); //调用EndInvoke
                Debug.WriteLine(string.Format("回调方法获取结果为Length:{0}", str.Length));
            }

    结果如下:

    开始计时:   0ms
    委托BeginInvoke:  26ms
    主线程运行耗时:1,029ms
    下载网站https://www.asp.net/结束
    进入回调方法体
    回调方法获取结果为Length:30543

    修改BeginInvoke的第二个state参数,我们传入del,可以直接用iar.AsyncState在回调函数中获取委托的引用。代码如下:

            delegate string MyDownLoadDel(string weburl);
            static void Main(string[] args)
            {
                Stopwatch watch = new Stopwatch();
                watch.Start();
                Debug.WriteLine(string.Format("开始计时:{0,4:N0}ms", watch.Elapsed.TotalMilliseconds));
                MyDownLoadDel del = new MyDownLoadDel(DownLoadWeb);
                IAsyncResult iar = del.BeginInvoke("https://www.asp.net/", new AsyncCallback(CallWhenDone), del);
                //new AsyncCallback 表示异步操作完成调用,如果直接写CallWhenDone,那么程序运行是同步完成
                Debug.WriteLine(string.Format("委托BeginInvoke:{0,4:N0}ms", watch.Elapsed.TotalMilliseconds));
                Thread.Sleep(1000);
                Debug.WriteLine(string.Format("主线程运行耗时:{0,4:N0}ms", watch.Elapsed.TotalMilliseconds));
                Console.ReadKey(); //暂停
            }
            public static string DownLoadWeb(string url)
            {
                WebClient wc = new WebClient();
                string str = wc.DownloadString(url);
                Debug.WriteLine(string.Format("下载网站{0}结束", url));
                return str;
            }
            public static void CallWhenDone(IAsyncResult iar)
            {
                Debug.WriteLine(string.Format("进入回调方法体"));
                MyDownLoadDel del = (MyDownLoadDel)iar.AsyncState; //获取委托的引用
                string str = del.EndInvoke(iar); //调用EndInvoke
                Debug.WriteLine(string.Format("回调方法获取结果为Length:{0}", str.Length));
            }

    结果如下:

    开始计时:   0ms
    委托BeginInvoke:  26ms
    主线程运行耗时:1,027ms
    下载网站https://www.asp.net/结束
    进入回调方法体
    回调方法获取结果为Length:30561

    可以看到主线程的运行没有影响,是在执行完DownLoadWeb方法后才会仅仅回调方法CallWhenDone中。

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

  • 相关阅读:
    iphone label相关的圆角处理(转)
    如何设置图片四个方向圆角属性
    iphone自动隐藏和显示工具栏和导航条
    重写系统黑色的TabBar
    awk正则表达式(转)
    AWK相关学习(转)
    C的 __FILE__, __LINE__的意思
    iphone UILabel 顶部对齐(top align)
    WPF笔记(4.5 MasterDetail数据绑定)——Data Binding
    CLR笔记:8.方法
  • 原文地址:https://www.cnblogs.com/hueychan/p/10575906.html
Copyright © 2020-2023  润新知