zoukankan      html  css  js  c++  java
  • 异步委托方式取消BackGroundWorker执行无循环的耗时方法

    边学习边分享,纯属抛砖引玉。

    线程的一个好处是异步的执行操作,在winform中,很多耗时操作执行时,为优化用户体验,避免长时间等待,从而运用线程技术异步的执行耗时操作,但不会阻塞主线程。

    最近系统很多耗时查询导致体验很差,于是想到了用BackGroundWorker异步处理。而且要支持某些耗时达到几十秒的操作,可以取消。

    BackGroundWorker有CancelAsync()这个方法。该方法只会将BackGroundWorker的CancellationPending属性设为true,但不会实际终止线程!网上找了些资料,代码如下

      private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
            {
    
            for (int i = 0; i < 100; i++)
                        {
                         if (backgroundWorker1.CancellationPending)  {
                                        e.Cancel = true;
                                        return;
                                    }
                        }
    }            

    即在doWork事件中,不停的循环判断是否执行了取消操作。这种适用于执行多次方法时,而且无法在某个方法执行时将线程取消。如果我doWork事件里,没有for循环,而是一次耗时的数据访问操作,那这样的处理没有任何意义。

    于是在下想到,可以在doWork事件里做如下处理

    1.异步的去执行耗时操作。

    2.while监视异步耗时操作是否完成,只要未完成就一直循环。循环内部判断是否执行了取消操作。如果执行了取消操作,则终止线程。代码如下

           private delegate int LongTimeDele();
           private bool isComplated=false;
           private int result=0;
    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
            {
    this.BeginInvoke(new LongTimeDele(()=>{
               Thread.Sleep(10000);////模拟耗时
         for (int i = 0; i < 100; i++)
                        {
                            result++;
                        }
            isComplated=true;
    }));
    
    while(!isComplated){
            
             if (backgroundWorker1.CancellationPending)  {
                                        e.Cancel = true;
                                        return;
                                    }
                        }
    }    

    试验之后,不知何故在this.BeginInvoke中的循环会阻塞主线程! 即界面卡主不动了,BeginInvoke应该是一步执行的,在下功力尚浅,不知何故,还请高手指教。

    于是想到了异步委托。直接上代码

    cs代码

        public partial class BackgroundWorkerTest : Form
        {
          
            public BackgroundWorkerTest()
            {
                InitializeComponent();
         
            }
            /// <summary>
            /// 建立一个委托,用来调用耗时操作。返回值是int,当然也可以是string、DataTable.....
            /// </summary>
            /// <returns></returns>
            private delegate int LongTimeDele();
         
    
            /// <summary>
            /// doWork事件
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
            {
    
                //声明一个委托的实例
                var waitHandller = new LongTimeDele(
                    () =>
                    {
                        //线程休眠10秒,模拟耗时操作
                        Thread.Sleep(10000);
                        var sumResult = 0;
                        for (int i = 0; i < 100; i++)
                        {
                            sumResult++;
                        }
                        return sumResult;
                    });
                //BeginInvoke,异步的去执行委托实例里的匿名方法。该方法返回的是一个IAsyncResult。返回值的状态会实时更新!
                var isa = waitHandller.BeginInvoke(null, null);
                //由于上面是异步,所以while的代码不会等待上面操作完成后执行,二者几乎同时执行
                //判断isa是否完成了,未完成的话(等待耗时操作)执行内部代码
                while (!isa.IsCompleted)
                {
                    //判断CancellationPending属性是否为true。如果你点击了取消button,这个属性就变成true了
                    if (backgroundWorker1.CancellationPending)
                    {
                        //取消操作
                        e.Cancel = true;
                        return;
                    }
                }
                //能执行到这里就说明操作完成了,把结果放进e中,传递给RunWorkerCompleted事件
                e.Result = waitHandller.EndInvoke(isa);
            
            }
    
            /// <summary>
            /// backgroundWorker执行完毕时事件,无论正常完成还是取消都会出发该事件
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
            {
                //只要不是类型EventArgs,你想要的数据e里面应有尽有!判断是否取消了操作
                if (e.Cancelled)
                {
                    MessageBox.Show("操作已取消");
                    return;
                    
                }
                //否则显示结果
                MessageBox.Show(e.Result.ToString());
            }
    
    
         
            /// <summary>
            /// 取消按钮事件
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void btnCancle_Click(object sender, EventArgs e)
            {
                //调用   backgroundWorker的CancelAsync()方法,该方法只会将CancellationPending属性设为true,并不会实际结束线程执行
                backgroundWorker1.CancelAsync();
            }
    
            /// <summary>
            /// 开始按钮事件
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void btnStart_Click(object sender, EventArgs e)
            {
                //判断线程是否繁忙
                if (backgroundWorker1.IsBusy)
                {
                    MessageBox.Show("系统繁忙");
                    return;
                }
                //空闲开始异步操作
                backgroundWorker1.RunWorkerAsync();
            }
        }
  • 相关阅读:
    洛谷P2331 [SCOI2005]最大子矩阵 DP
    洛谷P2216: [HAOI2007]理想的正方形 单调队列优化DP
    牛客练习赛38 E 出题人的数组 2018ccpc桂林A题 贪心
    zstu19一月月赛 duxing201606的原味鸡树
    gym/102021/J GCPC18 模拟拼图
    gym/102021/K GCPC18 背包dp算不同数和的可能
    洛谷 P2051 [AHOI2009]中国象棋 状态压缩思想DP
    洛谷 P1070 道路游戏 DP
    洛谷P2577 [ZJOI2005]午餐 打饭时间作为容量DP
    动态规划:插头DP
  • 原文地址:https://www.cnblogs.com/MLGB/p/4027244.html
Copyright © 2011-2022 走看看