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. java连接mysql :No Suitable Driver Found For Jdbc 解决方法

    今天出现编码出现了No suitable driver found for jdbc,又是找遍了网上的资料,基本上都说是以下个问题:    一是:连接URL格式出现了问题(Connection con ...

  2. Js 扩展

    计算字符串的字节长度 String.prototype.len = function () { return this.replace(/[^\x00-\xff]/g, 'xx').length; } ...

  3. 简单实用的Windows命令(二)

    昨天简单的记录了几个非常简单实用的Windows命令,不过我又想起来还有两个我在实际的工作中也是经常用到的命令——PING和IPCONFIG,不过我在工作中的使用都是非常简单的,用PING命令检测对应 ...

  4. assembly打包。

    --排除 <?xml version="1.0" encoding="UTF-8"?><assembly    xmlns="htt ...

  5. jQuery实现抖动效果

    //抖动效果 //intShakes:抖动次数:intDistance:抖动左右距离:intDuration:持续时间 jQuery.fn.shake = function (intShakes, i ...

  6. 【转】提高VR渲染速度的关键

    提高VR渲染速度的关键,这个教程比以往的教程都要重要很多,如果你是刚刚步入学习和上升阶段那么这将是你必须要看的东西,他会让你迅速提升技能达到比你死看书本好很多的效果,不多说上教程   VR的基本渲染方 ...

  7. GPUImage相关(转)

    3.滤镜 除了上面提到的美颜和水印之外,视频中还有很多其它的处理效果也在这个环节完成.七牛直播云提供的 SDK 在开放性设计基础之上,通过数据源回调接口,可以支持各种自定义滤镜的接入. 为了实现丰富的 ...

  8. 在Egret实现二维码长按识别

      Egret中二维码图片,是在canvas上,无法在微信上长按扫描识别. 由于微信长按识别二维码是截屏扫描原理,所以只要长按当前屏幕任意一张图片,都能够识别当前屏幕上的二维码. 这里把二维码放在ex ...

  9. 使用GIT进行源码管理——GIT托管服务

    虽然GIT是分布式代码管理,但是仍然需要一个集中存储服务以实现团队协作和代码备份的.对于企业的私有代码来说,大多是自建GIT托管服务.但对于开源项目和个人的私有项目,往往是选择一个GIT托管网站,这样 ...

  10. shopnc 二次开发 每日签到积分领取

    /* 开始shopnc!!!!! url:xxx.com/index.php?act=index&op=userjf 一个四线城市的半吊子程序员~ 实现:前台模板文件 随便加入<a> ...