在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("任务完毕");
}
}
}
程序运行效果图:
当然,以上只是个模拟程序,具体的业务和异常等等问题都未考虑太多,只是提供一个解决方案的思路。
如果你觉得有什么不妥或者错误,或者是更好的解决方案,欢迎联系反馈。
案例源码在这里 提取码:yklr
Copyright © 广州京杭网络科技有限公司 2005-2024 版权所有 粤ICP备16019765号
广州京杭网络科技有限公司 版权所有