C#多线程(三)

三,异步回调.顺序控制!,这次算是对委托使用的异步补充吧
在这里插入图片描述
【异步回调】

private void button3_Click(object sender, EventArgs e)
 {
            Console.WriteLine();
            Console.WriteLine("****************** 异步方法 start {0}********************", Thread.CurrentThread.ManagedThreadId);
            Action<string> action = new Action<string>(this.DoSomethingLong);
    
            #region 【回调】
        ////1 发起异步调用时,传递一个AsyncCallback委托实例,该实例会在异步调用完成后,由这个子线程去调用委托,就能保证顺序
        ////调用回调的委托,参数何来?其实是委托异步调用的结果作为参数去调用的
        ////AsyncState状态参数一般是用来提供给回调使用的,就是 BeginInvoke 方法中 第三个参数的值

        //asyncResult是异步调用的结果 但不是委托自身调用后的结果
        IAsyncResult asyncResult = null;
        AsyncCallback callback = new AsyncCallback((ar) =>
        {
            Console.WriteLine(object.ReferenceEquals(ar, asyncResult));
            Console.WriteLine(ar.AsyncState);
            if (ar.IsCompleted)
            {
                Console.WriteLine($"计算任务已完成 {Thread.CurrentThread.ManagedThreadId}");
            }
            //回调时候更新操作的UI
            this.BeginInvoke(new Action(() =>
            {
                this.label1.Text = $"当前计算已完成{Thread.CurrentThread.ManagedThreadId}";
            }));//会找主线程完成, CS还勉强可以这样做,但是BS是做不到的
        });
        for (int i = 0; i < 4; i++)
        {
            asyncResult = action.BeginInvoke("btnAsyncAdvanced_Click", callback, "aaa" + i);  //callback 回调,
        }            
        #endregion
        Console.ReadKey();
    }

【异步等待】

private void button4_Click(object sender, EventArgs e)
        {
            Console.WriteLine();
            Console.WriteLine("****************** 异步方法 start {0}********************", Thread.CurrentThread.ManagedThreadId);
            Action<string> action = new Action<string>(this.DoSomethingLong);

        #region 等待
        ////执行完计算后,提示用户说计算完成---如果用回调的方式,是没办法在请求结束后再去通知用户的,不能用子线程去完成通知的(尤其是BS,请求结束了就没办法再次通知)
        IAsyncResult asyncResult = action.BeginInvoke("btnAsyncAdvanced_Click", null, null);
        ////完成了顺序控制! 但是其实是主线程在等待计算,会阻塞(卡界面)
        ////为啥不就一个主线程?  是为了进度条,为了边计算边提示用户
        ////可能有延迟,最多延迟200ms
        int i = 0;
        while (!asyncResult.IsCompleted)  //回调完成,线程执行完毕
        {
            if (i < 10)
            {
                Console.WriteLine($"当前计算已经完成{i++ * 10}%");
            }
            else
            {
                Console.WriteLine($"当前计算已经完成99.99%");
            }
            Thread.Sleep(300);
        }
        Console.WriteLine("当前计算已完成");
        this.label1.Text = "当前计算已完成";
        #endregion
    }

【信号量】

private void button5_Click(object sender, EventArgs e)
        {
            Console.WriteLine();
            Console.WriteLine("****************** 异步方法 start {0}********************", Thread.CurrentThread.ManagedThreadId);
            Action<string> action = new Action<string>(this.DoSomethingLong);
            #region 信号量
            // 零延迟同步   asyncResult.AsyncWaitHandle.WaitOne(); //有很多重载,注意看
            //等待时不能做别的了。。其实是为了能并发,保证并发后都完成才继续
            IAsyncResult asyncResult = action.BeginInvoke("btnAsyncAdvanced_Click", null, null);

            //asyncResult.AsyncWaitHandle.WaitOne();//如果在做其他事情之前,先开始了等待,那么会阻塞,等待action执行方法完成

            Console.WriteLine("其他事情1");
            Console.WriteLine("其他事情2");
            Console.WriteLine("其他事情3");
            Console.WriteLine("其他事情4");
            Console.WriteLine("其他事情5");

            ////asyncResult.AsyncWaitHandle.WaitOne(-1);//一直等待
            Console.WriteLine($"计算等待前{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}");
            //asyncResult.AsyncWaitHandle.WaitOne(1000);//最多等待1000ms 超时就不等了 像调用接口时会用上
            //Console.WriteLine($"当前计算已完成{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}");
            //this.lblInfo.Text = "当前计算已完成";
            #endregion
        }

【EndInvoke】

private void button6_Click(object sender, EventArgs e)
        {
            Console.WriteLine();
            Console.WriteLine("****************** 异步方法 start {0}********************", Thread.CurrentThread.ManagedThreadId);
            Action<string> action = new Action<string>(this.DoSomethingLong);
            #region EndInvoke
            ////零延迟的等待   是为了获取委托自身调用的返回值
            //对于每个异步操作,只能调用一次 EndInvoke
            IAsyncResult asyncResult = action.BeginInvoke("btnAsyncAdvanced_Click", null, null);
            //Console.WriteLine($"计算等待前{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}");
            //action.EndInvoke(asyncResult);
            //asyncResult.AsyncWaitHandle.WaitOne(100);//最多等待1000ms 超时就不等了 像调用接口时会用上
            //Console.WriteLine($"当前计算已完成{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}");
            //asyncResult是异步调用的结果 但不是委托自身调用后的结果


            Func<int> func = new Func<int>(() =>
              {
                  Thread.Sleep(2000);
                  return DateTime.Now.Year;
              });
            int iResult = func.Invoke();//委托自身调用后的结果
            Console.WriteLine($"委托自身的返回:{ iResult }");

            IAsyncResult iAsyncResult = func.BeginInvoke((ar) =>
            {
                int iResultAsyncIn = func.EndInvoke(ar); //回调结束后接受返回值
                Console.WriteLine($"通过委托自身的异步调用获取返回值:{iResultAsyncIn}");

            }, null);//异步调用的结果

           //EndInvoke//只能够调用一次,一对一,不然出现异常
            #endregion
        }

暂时写到这,欢迎指教!

猜你喜欢

转载自blog.csdn.net/weixin_42780928/article/details/92801884