Task执行多个任务并取得汇总结果(不卡界面)

如何执行多个Task任务的汇总结果,并且不会卡界面的方法:

解决步骤:

1、单个且有返回值的Task任务,将结果显示到界面上,分析卡界面的原因;

2、单个且有返回值的Task任务,将结果显示到界面上,不卡界面;

3、多个且有返回值的Task任务集合,将结果汇总后显示到界面上,不卡界面;

 

按下按钮开始计算一个耗时的加法,并将加法结果返回显示到界面上。如下:

 

 

 

 

 


 

1、单个且有返回值的Task任务,将结果显示到界面上,分析卡界面的原因;

        private void button1_Click(object sender, EventArgs e)
        {
            Task<int> t = new Task<int>(() => GetSum(2, 3));
            t.Start();
            label1.Text = "结果:" + t.Result.ToString();
        }

        int GetSum(int v1, int v2)
        {
            Thread.Sleep(2000);
            return v1 + v2;
        }

分析:卡界面的原因是发生在获取线程结果时,即:t.Result这里需要等,而不是t.Start()。

 

2、单个且有返回值的Task任务,将结果显示到界面上,不卡界面;

分析1中的原因,因为t.Result这里需要等待,导致界面卡,所以可以将等结果的这一步放到一个新线程中等。如下:

        //不卡界面,将获取结果的耗时操作放入另一线程中等待
        private void button1_Click(object sender, EventArgs e)
        {
            Task<int> t = new Task<int>(() => GetSum(3, 3));
            t.Start();

            Task.Run(() =>
            {
                int result = t.Result;
                this.Invoke(new Action(() =>
                {
                    //label1.Text = "结果:" + t.Result.ToString();//这种同样卡界面,相当于委托主线程去等结果
                    label1.Text = "结果:" + result;//不卡界面,获取结果在子线程中等,这里只是更新UI
                }));
            });
        }

 

3、多个且有返回值的Task任务集合,将结果汇总后显示到界面上,不卡界面;

通过上面的方法,多个Task任务集合与单个Task任务获得汇总结果并显示的方法是相似的,如下:

 

        //等待多个线程的结果,并显示,第一种方法
        private void button1_Click(object sender, EventArgs e)
        {
            List<Task<int>> taskList = new List<Task<int>>();
            Task<int> t1 = new Task<int>(() => GetSum(1, 3));
            Task<int> t2 = new Task<int>(() => GetSum(2, 3));
            Task<int> t3 = new Task<int>(() => GetSum(3, 3));
            taskList.Add(t1);
            taskList.Add(t2);
            taskList.Add(t3);

            taskList.ForEach((task) => task.Start());//全部启动线程

            Task.Run(() =>
            {
                int sum = 0;
                foreach (var item in taskList)
                {
                    sum += item.Result;
                }
                this.Invoke(new Action(() =>
                {
                    label1.Text = sum.ToString();
                }));
            });
        }

        int GetSum(int v1, int v2)
        {
            Thread.Sleep(5000);
            return v1 + v2;
        }

 

 

4、采用异步,多个且有返回值的Task任务集合,将结果汇总后显示到界面上,不卡界面;参考:异步多线程解决界面卡顿问题 - hanzq_go - 博客园 (cnblogs.com)

        //等待多个线程的结果,并显示,第二种方法
        private async void button1_Click(object sender, EventArgs e)
        {
            List<Task<int>> taskList = new List<Task<int>>();
            Task<int> t1 = new Task<int>(() => GetSum(1, 3));
            Task<int> t2 = new Task<int>(() => GetSum(2, 3));
            Task<int> t3 = new Task<int>(() => GetSum(3, 3));
            taskList.Add(t1);
            taskList.Add(t2);
            taskList.Add(t3);

            taskList.ForEach((task) => task.Start());//全部启动线程

            int[] resultList = await Task.WhenAll(taskList.ToArray());            
            label1.Text = resultList.Sum().ToString();
        }

        int GetSum(int v1, int v2)
        {
            Thread.Sleep(5000);
            return v1 + v2;
        }

 

总结:

所以想不卡界面,就不要在主线程等待r.result。可以新建一个线程执行等待结果操作。
除非方法本身是异步方法,如whenAll(),它可以使用await关键字直接在发起线程等待,不会阻塞界面。

另外:Task.When All和Task.Wait All的区别

Task.WaitAll();无返回值。
Task.WhenAll();有返回值。可以直接拿到任务完成后的数据或者取得任务运行状态。

 

posted on 2022-10-31 11:16  hanzq_go  阅读(447)  评论(0编辑  收藏  举报

导航