• C#异步委托的三种实现 BeginInvoke / EndInvoke / IsCompleted


    • 本文将介绍C#异步委托的三种实现方式,并给出相关示例代码及解析。

    注意事项

      1. 用委托开启线程的前提是:创建项目时必须选择“.NET Framework",如果选择的是”.Net Core“,在调用BeginInvoke时,系统会报错”Operation is not supported on this platform.“。
      1. 异步调用的另一个前提是:委托的方法列表中只能包含一个方法。

    等待至完成

    • 通过BeginInvoke和EndInvoke实现。
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace FrameworkDemo
    {
        public delegate long MyDel(int a, int b);
        class Program
        {
            static long sum(int a, int b) {
                Thread.Sleep(10 * 1000);
                return a + b;
            }
            static void Main(string[] args)
            {
                // 异步委托操作描述
                IAsyncResult res = null;
    
                long result = 0;
                AsyncCallback callback = ar =>
                {
                    // 输出结果:“计算结果为:11”
                    Console.WriteLine($"{ar.AsyncState}{result}");
                };
                MyDel del = new MyDel(sum);
                // BeginInvoke开启异步调用
                // res的打印结果为System.Runtime.Remoting.Messaging.AsyncResult
                res = del.BeginInvoke(3, 8, callback, "计算结果为");  
                // 等待线程结束,并获取返回值
                result = del.EndInvoke(res);
                Console.ReadLine();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • BeginInvoke函数的最后两个参数分别是一个回调函数,以及传入这个回调函数的参数。当委托线程运行结束后,会自动运行这个回调函数。之前的参数个数及类型取决于定义委托时参数的类型和个数。
    • IAsyncResult类型表示对异步委托操作的描述,一调用异步委托,就立刻会在主函数中得到这个返回值,打印结果为“System.Runtime.Remoting.Messaging.AsyncResult”。
    • EndInvoke会把主线程卡主,知道异步委托方法结束,此时将之前拿到的异步委托操作描述作为参数传入,即可获得异步委托函数的真正返回值。

    轮询模式

    • 通过IsCompleted实现。
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace FrameworkDemo
    {
        public delegate long MyDel(int a, int b);
        class Program
        {
            static long sum(int a, int b) {
                Thread.Sleep(10 * 1000);
                return a + b;
            }
            static void Main(string[] args)
            {
                // 异步委托操作描述
                IAsyncResult res = null;
    
                long result = 0;
                AsyncCallback callback = ar =>
                {
                    // 输出结果:“计算结果为:11”
                    Console.WriteLine($"{ar.AsyncState}{result}");
                };
                MyDel del = new MyDel(sum);
                // BeginInvoke开启异步调用
                // res的打印结果为System.Runtime.Remoting.Messaging.AsyncResult
                res = del.BeginInvoke(3, 8, callback, "计算结果为");
                while (!res.IsCompleted) {
                    /*
                     一系列想要的操作
                     */
                }
                // 等待线程结束,并获取返回值
                result = del.EndInvoke(res);
                Console.ReadLine();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 之前我们调用BeginInvoke后,直接调用EndInvoke,这使得主线程一直卡主,直到委托线程返回,通过IsComplated进行轮询线程状态,我们可以在循环中利用等待时间,执行一些别的想要的工作。

    回调

    • 关于回调函数,比较标准的写法如下:
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.Remoting.Messaging;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace FrameworkDemo
    {
        public delegate long MyDel(int a, int b);
        class Program
        {
            static long sum(int a, int b) {
                Thread.Sleep(10 * 1000);
                return a + b;
            }
            // 异步委托执行完成后需要调用的回调函数
            static void testCallback(IAsyncResult ar) {
                System.Runtime.Remoting.Messaging.AsyncResult varResult =
                 (System.Runtime.Remoting.Messaging.AsyncResult)ar;
                MyDel test = (MyDel)varResult.AsyncDelegate;
                long result = test.EndInvoke(ar);
                Console.WriteLine($"{ar.AsyncState}: {result}");
            }
            static void Main(string[] args)
            {           
                MyDel del = new MyDel(sum);
                AsyncCallback asyncTest = new AsyncCallback(testCallback);
                del.BeginInvoke(3, 8, asyncTest, "计算结果为");
                Console.ReadLine();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 当异步委托运行结束后,系统会自动调用回调函数,并将异步委托描述信息IAsyncResult作为参数传入回到函数中,因此我们需要做的就是解析异步委托描述信息。
  • 相关阅读:
    为互连智能合约Connected Contracts使用Axelar SDK
    py9_详解 Python 类属性/类方法 以及如何转换类方法和静态方法
    MySQL数据库之事务
    笔记 | 十六进制不进位加法
    印刷行业的ERP软件的领头羊
    数字化餐饮| 刘大厨湘菜馆进杭州,开场及巅峰
    QT实现任意阶贝塞尔曲线绘制
    有了这份2022Java面试八股文,进大厂稳了!
    k8s查看pod日志的几种方法
    前端中有序标签的使用
  • 原文地址:https://blog.csdn.net/Nire_Yeyu/article/details/133203267