http://2sharings.com/2014/net-4-5-task-run-parallel-for-winform-cross-multiple-threads-update-ui-demo

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

 
 
 
 
 

C#

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

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

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

按照以上的应用场景,我做了一个模拟的小实例,实现代码:

 
 
 
 
 

C#

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
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("任务完毕");
    }
  }
}

程序运行效果图:

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

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

  1. C#中禁止跨线程直接访问控件

    C#中禁止跨线程直接访问控件,InvokeRequired是为了解决这个问题而产生的,当一个控件的InvokeRequired属性值为真时,说明有一个创建它以外的线程想访问它.此时它将会在内部调用ne ...

  2. winform中更新UI控件的方案介绍

    这是一个古老的话题...直入主题吧! 对winfrom的控件来说,多线程操作非常容易导致复杂且严重的bug,比如不同线程可能会因场景需要强制设置控件为不同的状态,进而引起并发.加锁.死锁.阻塞等问题. ...

  3. WinForm/Silverlight多线程编程中如何更新UI控件的值

    单线程的winfom程序中,设置一个控件的值是很easy的事情,直接 this.TextBox1.value = "Hello World!";就搞定了,但是如果在一个新线程中这么 ...

  4. winform中如何在多线程中更新UI控件--ListView实时显示执行信息

    1.在winform中,所有对UI的操作,都得回到UI线程(主线程)上来,才不会报错 线程间操作无效: 从不是创建控件的线程访问它. 2.在winform中,允许通过Control.invoke对控件 ...

  5. C#学习之在辅助线程中修改UI控件----invoke方法

    Invoke and BeginInvoke 转载地址:http://www.cnblogs.com/worldreason/archive/2008/06/09/1216127.html 在Invo ...

  6. ios 中的UI控件学习总结(1)

    UIKit框架提供了非常多功能强大又易用的UI控件 下面列举一些在开发中可能用得上的UI控件 UIButton 按钮 UILabel 文本标签 UITextField 文本输入框 UIImageVie ...

  7. 关于libgdx中UI控件的旋转和缩放的备忘

    最近遇到这样一个问题,定义了一个ImageButton后,想对按钮进行下旋转,结果setRotation(-90f),不起作用.后来在官网上找到了原因 关于UI控件的旋转 缩放官网上有这样一段话(链接 ...

  8. C#.NET使用Task,await,async,异步执行控件耗时事件(event),不阻塞UI线程和不跨线程执行UI更新,以及其他方式比较

    使用Task,await,async,异步执行事件(event),不阻塞UI线程和不跨线程执行UI更新 使用Task,await,async 的异步模式 去执行事件(event) 解决不阻塞UI线程和 ...

  9. C#中Windows Media Player控件使用实例|方法

    Windows Media Player控件Windows Media Player是一种媒体播放器,可以播放当前最流行的音频.视频文件和大多数混合型的多媒体文件.为了便于程序的开发,Visual S ...

随机推荐

  1. nodejs-express 报错View is not a constructor

    可能是express版本问题 view修改为views – app.set('views',__dirname + '/views');

  2. 适合最新版docker自定义启动配置

    docker不断发布新版本,以前默认的在 /etc/default/docker里修改,但是新版已经不推荐了 注意: 一些文章推荐在 /lib/systemd/system/docker.servic ...

  3. NBU AIX ORACLE10G RAC恢复到AIX单实例(表空间恢复)

    ln -s /usr/openv/netbackup/bin/libobk.a64 /oraclev3/product/10.2.0/lib/libobk.a不建软连接会报如下错误: using ta ...

  4. Intel汇编语言程序设计学习笔记1

    第一章 汇编器链接器:汇编器将汇编语言翻译成机器语言,链接器将单个文件合并为可执行文件 intel 80X86系列处理器的汇编语言与VAX或者motorala 68x00等系统的汇编是否相同?不相同, ...

  5. 四、maya python plugin

    只是作简单的了解. 1区别 (1)Python scripts:可以在Maya的script editor 执行.用于扩展maya.cmd模块. The import statement below ...

  6. 华为OJ题目:刷题

    题目描述: 新入职华为的小伙伴们都有在oj上面刷题的任务,共需要刷100道初级题,45道中级题,5道高级题,其中,做出来的高级题如果超标可以当初级或者中级题,做出来的中级题如果超标可以当初级题.每天, ...

  7. 网站搭建 so easy

    服务器(国际购买):http://www.gigsgigscloud.com/ 域名(阿里云): 解析到服务器       服务器需要安装 1.putty 2.CuteFTP(自己感觉这个靠谱点) / ...

  8. 初尝 JFinal 项目(一)

    temp1: JFinal项目与JAVA项目类似,有属性方法.操作方法.Sql语句操作.jdbc.配置文件 对比:|| JAVA: Bean / Srv(Server) / SqlMap / jdbc ...

  9. MySql生日闰月处理

    1. 科普下润年: ①.非整百年能被4整除的为闰年.(如2004年就是闰年,2100年不是闰年) ②.整百年能被400整除的是闰年.(如2000年是闰年,1900年不是闰年)   2. 例: 例如:当 ...

  10. Jquery DOM 操作列表

    jQuery 文档操作方法 这些方法对于 XML 文档和 HTML 文档均是适用的,除了:html(). jQuery 属性操作方法 下面列出的这些方法获得或设置元素的 DOM 属性. 这些方法对于 ...