• C#高级编程之Invoke和BeginInvoke


    Invoke同步(按顺序)与BeginInvoke异步(无序)

    Invoke

    在拥有此控件的基础窗口句柄的线程上执行委托,同步的。

    BeginInvoke

    在创建控件的基础句柄所在线程上异步执行委托。

    如下所示:

             /// <summary>
            /// 同步方法:发起调用,代码按照顺序逐行执行。---有顺序(线程ID是同一个--同一线程来执行的所有操作)
            /// </summary>
            private static void ExecuteSyncMethod()
            {
                Action<string> action = new Action<string>(DoSomeThing);
                action.Invoke("同步执行 DoSomeThing 0");
                Console.WriteLine("---------------------");
            }
    //异步方法:发起调用:没有等待完成,直接进入到下一行,启动一个新的线程来执行动作(线程ID不一样)
            //异步方法:不卡顿界面:UI(主线程)闲置,计算任务交给了子线程去执行了。
            //同步方法:卡界面,因为主线程忙于计算,根本无暇他顾。
            /*异步调用Async
             开辟一个新的线程去执行BeginInvoke[调用DoSomeThing方法],主线程不会等待这句话执行完,会立即去执行
            下面的action("同步执行 DoSomeThing 1");action("同步执行 DoSomeThing 2");语句
             异步调用Async是无序的,那如果想按照顺序实现异步,那怎么办呢,使用回调函数
             */
            private static void ExecuteAsyncMethod(Action<string> action)
            {
                //异步无序调用 .net core不支持BeginInvoke异步调用,是个坑
                action.BeginInvoke("异步无序执行 DoSomeThing", null, null);
                action("同步执行 DoSomeThing 1");
                action("同步执行 DoSomeThing 2");
                action("同步执行 DoSomeThing 3");
                Console.WriteLine("执行结束");
                Console.ReadKey();
            }
    static void Main(string[] args)
            {
    ExecuteSyncMethod();
    Action<string> action = new Action<string>(DoSomeThing);
    ExecuteAsyncMethod(action);

     可以看到同步的线程ID与BeginInvoke启动的线程ID是不同的。

    下面的例子与上面相似(BeginInvoke启动的是一个无序的新线程)

        private static void ExecuteCallBackFunc()
            {
                Console.WriteLine($"Func start,threadID={Thread.CurrentThread.ManagedThreadId}");
                Action<string> action = new Action<string>(DoSomeThing);
                action.BeginInvoke("Excuting Method", null, null);
                Console.WriteLine("ExecuteCallBackFunc is execute filished1");
                Console.WriteLine("ExecuteCallBackFunc is execute filished2");
                Console.WriteLine("ExecuteCallBackFunc is execute filished3");
            }

    BeginInvoke下的实现顺序执行

    无参回调函数

    那如果想 Executing Method执行完后再按照顺序打印"execute filished",如果做呢?可以通过回调函数,如下所示:

        private static void DoSomeThing(string methodname)
            {
                Thread.Sleep(1000);
                Console.WriteLine($"{DateTime.Now.ToString()} method: {methodname},threadID=[{Thread.CurrentThread.ManagedThreadId}]");
            }
    
            private static void ExecuteCallBackFunc()
            {
                Console.WriteLine($"Func start,threadID={Thread.CurrentThread.ManagedThreadId}");
                Action<string> action = new Action<string>(DoSomeThing);
                //public delegate void AsyncCallback(IAsyncResult ar);AsyncCallback是一个形参为IAsyncResult的无返回值的委托
                //异步回调:执行完Excuting Method的动作后才执行execute filished1【相当于一堆动作执行完毕后,再执行点动作--回调】
                AsyncCallback callback = arr =>
                {
                    Console.WriteLine("ExecuteCallBackFunc is execute filished1");
                    Console.WriteLine("ExecuteCallBackFunc is execute filished2");
                    Console.WriteLine("ExecuteCallBackFunc is execute filished3");
                };
                action.BeginInvoke("Excuting Method", callback, null);
    
            }

     带参数回调函数

     如果需要往异步回调委托中传递参数,如果传递呢?可以通过给BeginInvoke第三个参数传值,在异步委托的内部,可以通过AsyncState获取到参数的值

    有返回值的异步委托使用

             //2如果想要获取返回值呢
                Func<int> func = () =>
                {
                    Thread.Sleep(3000);
                    return DateTime.Now.Year;
                };
                IAsyncResult asyncResult = func.BeginInvoke(callback, "weiyin");
                while (!asyncResult.IsCompleted)
                {
                    Console.WriteLine("1222222");
                    /*Thread.Sleep(20)*/;
                }

    上面asyncResult描述了委托执行的情况,如是否执行完毕,是否需要等待等相关属性。IAsyncResult接口信息如下:

    //     表示异步操作的状态。
        [ComVisible(true)]
        public interface IAsyncResult
        {
            //
            // 摘要:
            //     获取一个值,该值指示异步操作是否已完成。
            //
            // 返回结果:
            //     如果操作已完成,则为 true;否则为 false。
            bool IsCompleted { get; }
            //
            // 摘要:
            //     获取用于等待异步操作完成的 System.Threading.WaitHandle。
            //
            // 返回结果:
            //     用于等待异步操作完成的 System.Threading.WaitHandle。
            WaitHandle AsyncWaitHandle { get; }
            //
            // 摘要:
            //     获取一个用户定义的对象,该对象限定或包含有关异步操作的信息。
            //
            // 返回结果:
            //     一个用户定义的对象,限定或包含有关异步操作的信息。
            object AsyncState { get; }
            //
            // 摘要:
            //     获取一个值,该值指示异步操作是否同步完成。
            //
            // 返回结果:
            //     如果异步操作同步完成,则为 true;否则为 false。
            bool CompletedSynchronously { get; }
        }
    View Code

    EndInvoke获取异步委托的返回值

    而如何获取该委托执行后的结果呢?通过执行EndInvoke接收异步委托的返回值。

        Console.WriteLine($"Func start,threadID={Thread.CurrentThread.ManagedThreadId}");
                AsyncCallback callback = arr =>
                {
                    Console.WriteLine("传入的参数为:"+arr.AsyncState);
                    Console.WriteLine($"threadID=[{Thread.CurrentThread.ManagedThreadId}]");
                    Console.WriteLine("ExecuteCallBackFunc is execute filished1");
                    Console.WriteLine("ExecuteCallBackFunc is execute filished2");
                    Console.WriteLine("ExecuteCallBackFunc is execute filished3");
                };
                //如果需要往异步回调委托中传递参数,就给BeginInvoke第三个参数传值,在异步委托的内部,可以通过AsyncState获取到参数的值
                //1.控制了顺序:通过异步回到委托
                //action.BeginInvoke("Excuting Method", callback, "this is weiyin");
                //2如果想要获取返回值呢
                Func<int> func = () =>
                {
                    Thread.Sleep(2000);
                    Console.WriteLine("正在执行有返回值的异步委托");
                    Console.WriteLine($"{DateTime.Now.ToString()},threadID=[{Thread.CurrentThread.ManagedThreadId}]");
                    return DateTime.Now.Year;
                };
                IAsyncResult asyncResult = func.BeginInvoke(callback, "weiyin");
                //2.IsCompleted完成等待
                int i = 0;
                Console.WriteLine($"Main threadID=[{Thread.CurrentThread.ManagedThreadId}]");
                while (!asyncResult.IsCompleted)
                {
                    if (i < 9)
                    {
                        Console.WriteLine($"正在玩命加载中。。,已经完成{++i * 10}%");
                    }
                    else
                    {
                        Console.WriteLine($"正在玩命加载中。。,已经完成99.999%");
                    }
                    Thread.Sleep(200);
                }
                Console.WriteLine("加载完成。。");
                //以上回调函数和IsCompleted 两种都是为了等待任务的完成。
                {
                    //3 WaitOne
                    asyncResult.AsyncWaitHandle.WaitOne();//一直等待任务完成
                    asyncResult.AsyncWaitHandle.WaitOne(-1);//一直等待任务完成
                    asyncResult.AsyncWaitHandle.WaitOne(3000);//最多等待3000ms,如果超时了,就不等待了
                }
                int iresult = func.EndInvoke(asyncResult);
                Console.WriteLine($"iresult异步执行的委托返回值={iresult}");
            }

     总结:

    调用Invoke会同步按顺序执行委托绑定的方法;

    调用BeginInvoke单独启动一个线程,异步执行委托绑定的方法,其执行是没有顺序的。

    如果想在异步执行委托的同时顺序执行逻辑:可以通过回调函数执行完异步委托绑定的方法的逻辑后,再执行回调函数里面的逻辑。可以给回调函数传参。如果想获取异步委托执行后的返回值,可以通过EndInvoke获取。异步委托执行绑定的方法的相关状态信息存储IAsyncResult信息中。

  • 相关阅读:
    设计模式的C语言应用-外观模式-第八章
    00071_基本类型包装类
    win7不能在同一窗口打开文件夹,解决办法
    浏览器主页被搜狗劫持的解决办法,慎用宁美国度的安装软件,慎用不正规来源的软件
    使用inotify-tools与rsync构建实时备份系统
    浅淡 RxJS WebSocket
    SpringMVC大文件(百M以上)的上传下载实现技术
    C#.NET大文件(百M以上)的上传下载实现技术
    JSP大文件(10G以上)的上传下载实现技术
    JAVA大文件(10G以上)的上传下载实现技术
  • 原文地址:https://www.cnblogs.com/shuzhongke/p/14136033.html
Copyright © 2020-2023  润新知