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);

C#高级编程之Invoke和BeginInvoke

 可以看到同步的线程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);

        }

C#高级编程之Invoke和BeginInvoke

 带参数回调函数

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

C#高级编程之Invoke和BeginInvoke

有返回值的异步委托使用

         //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接口信息如下:

C#高级编程之Invoke和BeginInvoke
//     表示异步操作的状态。
    [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接收异步委托的返回值。

    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}");
        }

C#高级编程之Invoke和BeginInvoke

 

C#高级编程之Invoke和BeginInvoke

上一篇:api2html api+mustache 模式的website 生成


下一篇:C#一些重要的功能(待补充)