首页 / C#开发 / 正文

.NET 4.5中使用Task.Run和Parallel.For()实现的C# Winform多线程任务及跨线程更新UI控件综合实例

17668 2评论 发布于: 2014-11-12 读完约需11分钟

在C# WINFORM的开发中,难免会遇到多线程的开发以提高程序的执行效率。
自己刚才开始在做多线程的开发时也遇到了很多这方面的问题,比如:如何使用并实现多线程功能、跨线程更新UI控件等问题。
还记得最初使用的是System.Threading命名空间下的Thread类来实现的:

var t = new Thread(new ThreadStart(() => { //具体实现}));
t.IsBackground = true;
t.Start();

功能实现上是没有什么问题的,但总觉得使用上不是很方便,于是使用了.NET Framework 4+版本中提供的Parallel在实现多线程的程序功能开发。再结合.NET4.5版本中的Task.Run()的ContinueWith()方法来实现相对更高级的循环任务的多线程任务。

具体的应用场景为:有一个数据量比较大(几百万)的表,需要将这个表中的每条记录取出来用程序进行处理,然后再更新到表中去。
目前单线程的处理程序已实现,这时为了达到快速处理数据的目的,我们就需要使用多线程来批量处理这些数据了。但批量处理时我们又不能一次性把表中的所有数据都读出来。
所以,我们需要将数据分批少量地取出来,再处理,然后更新回去。按照以上的应用场景,我做了一个模拟的小实例,实现代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace CrossThreadsUpdateUIDemo
{
  public partial class FrmMain : Form
  {
    /// <summary>
    /// 任务队列
    /// </summary>
    private Queue<int> _queueTask = new Queue<int>();
    /// <summary>
    /// 任务循环执行次数
    /// </summary>
    private static int _executeCounter = 0;

    private static object locker = new object();
    public FrmMain()
    {
      InitializeComponent();
    }

    #region Methods

    /// <summary>
    /// 更新UI控件
    /// </summary>
    /// <param name="message"></param>
    private void UpdateLogUI(string message)
    {
      BeginInvoke(new Action(() =>
      {
        lstLog.Items.Insert(0, message);
      }));
    }

    /// <summary>
    /// 模拟加载数据
    /// </summary>
    private void LoadData()
    {
      for (int i = 1; i <= 5; i++)
      {
        _queueTask.Enqueue(i);
      }
    }

    #endregion

    private async void btnStart_Click(object sender, EventArgs e)
    {
      var t = new Thread(new ThreadStart(() => { }));
      t.IsBackground = true;
      t.Start();
      _executeCounter = 0;
      //lstLog.Items.Clear();
      LoadData();
      do
      {
        if (_queueTask == null || _queueTask.Count <= 0)
        {
          break;
        }
        await Task.Run(() =>
        {
          try
          {
            var num = 0;
            _executeCounter++;
            UpdateLogUI(string.Format("开始第{0}次任务,总任务数:{1}...", _executeCounter, _queueTask == null ? 0 : _queueTask.Count));
            var total = _queueTask.Count;
            Parallel.For(0, total, new ParallelOptions { MaxDegreeOfParallelism = 3 }, t =>
            {
              if (num <= 3)
              {
                Thread.Sleep(500);
                num++;
              }
              while (_queueTask.Count > 0)
              {
                var rand = new Random();
                var sleep = rand.Next(500, 5000);
                int task = 0;
                if (_queueTask.Count > 0)
                {
                  lock (_queueTask)
                  {
                    task = _queueTask.Dequeue();
                  }
                }
                UpdateLogUI(string.Format("Task {0} start,Sleep:{1}...", task, sleep));
                Thread.Sleep(sleep);
                UpdateLogUI(string.Format("Task {0} completed.", task));
              }
            });
          }
          catch (Exception ex)
          {
            UpdateLogUI(string.Format("错误:{0}", ex.Message));
          }
        }).ContinueWith(t =>
        {
          UpdateLogUI(string.Format("第{0}次任务执行完成.", _executeCounter));
          if (_executeCounter < 5)
          {
            LoadData();
          }
        });
      }
      while (_queueTask.Count > 0);
      UpdateLogUI("任务完毕");
    }
  }
}

程序运行效果图:
cross-thread-update-ui

当然,以上只是个模拟程序,具体的业务和异常等等问题都未考虑太多,只是提供一个解决方案的思路。
如果你觉得有什么不妥或者错误,或者是更好的解决方案,欢迎联系反馈。
案例源码在这里 提取码:yklr

特别说明:本文所使用的案例是基于.NET 4.5版本开发和运行的。

版权声明:本作品系原创,版权归码友网所有,如未经许可,禁止任何形式转载,违者必究。

上一篇: 分享两个.NET(C#版)日期和Unix TimeStamp相互转换的方法

下一篇: 微软发布Visual Studio 2013 Update 4 (2013.4) RTM

本文永久链接码友网 » .NET 4.5中使用Task.Run和Parallel.For()实现的C# Winform多线程任务及跨线程更新UI控件综合实例

分享扩散:

发表评论

登录用户才能发表评论, 请 登 录 或者 注册

热门评论

sk (2015-02-25 22:49)

学习啦~~~
回复 赞(0)

lbxp (2014-11-27 09:15)

正在学习多线程方面的,非常有用的知识点介绍!!!
回复 赞(0)