线程封装组件(BackgroundWorker)和线程(Thread)
BackgroundWorker是微软的在.net Framwork中添加的一个组件,主要对线程的访问提供了一种安全的方式。简单的说就是对Thread的一次封装。
BackgroundWorker位于System.ComponentModel下,是一个继承了Component的组件,微软官方的解释为:Executes an operation on a separate thread.就是说,开始一个新的线程执行操作。
首先介绍一下BackgroundWorker的相关属性和方法:
属性:
WorkerReportsProgress:是否可以报告进度。
WorkerSupportsCancellation:是否允许异步中止。
IsBusy:是否在运行。
CancellationPending:判断BackgroundWorker是否已经异步取消。
方法:
RunWorkerAsync:开始执行任务。触发DoWork事件
ReportProgress:异步提醒,触发ProgressChanged事件,但是这个如果可以使用,必须设置WorkerReportsProgress为True
CancelAsync:取消BackgroundWorker操作。
事件:
DoWork:执行RunWorkerAsync后触发,异步执行的认为。
ProgressChanged:执行ReportProgress时触发,异步获得进度。
RunWorkerCompleted:线程结束时触发,主要有成功结束,发生异常或者取消时发生。
Thread相对来说就简单了,但是使用起来就比较麻烦了。Thread位于System.Threading的名空间下,是一个可以独立创建和操作一个线程,并且对线程进行设置优先级和获得状态的一个不可继承的类。
下面是我做的一个例子,来比较他们两个的使用。
建立一个窗体,放置了两个TextBox,分别为设置开始和结束的Progree的值,放置两个ProgressBar,分别设置为线程的Progressbar和BackGroundWorker的ProgressBar。另外放置按钮为StartBackGroundWorker,StartThread,CancelBackGroundWorker,CancelThread和PauseThread。
BackGroundWorker的使用就非常简单:
2 /// Handles the Click event of the btnBackGroundWorker control.
3 /// </summary>
4 /// <param name="sender">The source of the event.</param>
5 /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
6 private void btnBackGroundWorker_Click(object sender, EventArgs e)
7 {
8 StartFrom = Convert.ToInt32(txtStart.Text);
9 EndTo = Convert.ToInt32(txtEnd.Text);
10
11 progressBarThread.Minimum = StartFrom;
12 progressBarThread.Maximum = EndTo;
13
14 this.btnBackGroundWorker.Enabled = false;
15
16 this.backgroundWorker.RunWorkerAsync();
17 }
18
19 /// <summary>
20 /// Handles the DoWork event of the backgroundWorker control.
21 /// </summary>
22 /// <param name="sender">The source of the event.</param>
23 /// <param name="e">The <see cref="System.ComponentModel.DoWorkEventArgs"/> instance containing the event data.</param>
24 private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
25 {
26 for (int nValue = StartFrom; nValue <= EndTo; nValue++)
27 {
28 if (this.backgroundWorker.CancellationPending)
29 {
30 e.Cancel = true;
31 return;
32 }
33 this.backgroundWorker.ReportProgress(nValue);
34 Thread.Sleep(200);
35 }
36 }
37
38 /// <summary>
39 /// Handles the ProgressChanged event of the backgroundWorker control.
40 /// </summary>
41 /// <param name="sender">The source of the event.</param>
42 /// <param name="e">The <see cref="System.ComponentModel.ProgressChangedEventArgs"/> instance containing the event data.</param>
43 private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
44 {
45 this.prgProcessBackGroundWorker.Value = e.ProgressPercentage;
46 }
47
48 /// <summary>
49 /// Handles the RunWorkerCompleted event of the backgroundWorker control.
50 /// </summary>
51 /// <param name="sender">The source of the event.</param>
52 /// <param name="e">The <see cref="System.ComponentModel.RunWorkerCompletedEventArgs"/> instance containing the event data.</param>
53 private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
54 {
55 // 取消
56 if (e.Cancelled)
57 {
58 MessageBox.Show("Cancelled");
59 }
60 // 出现错误
61 else if (e.Error != null)
62 {
63 MessageBox.Show(e.Error.Message + Environment.NewLine + e.Error.StackTrace);
64 }
65 // 完成
66 else
67 {
68 MessageBox.Show("Completed");
69 this.btnBackGroundWorker.Enabled = true;
70 }
71 }
72
73 /// <summary>
74 /// Handles the Click event of the btnCancelBackgroundWoker control.
75 /// </summary>
76 /// <param name="sender">The source of the event.</param>
77 /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
78 private void btnCancelBackgroundWoker_Click(object sender, EventArgs e)
79 {
80 this.backgroundWorker.CancelAsync();
81 }
Thread的使用就比较麻烦了,对于尤其是对异步提醒来说,需要写委托,代码量是很多,但是对于BackgroundWorker来说,却没有线程暂停和继续的方法。但是对于一般的来说,这些功能也是不用的,而且在微软的文档中还提到了,Thread的Resume和Suspend已经不推荐使用。
2 delegate void DelegateType(int x);
3 DelegateType TheDelegate;
4
5 // ProgressBar的开始和结束值
6 int StartFrom, EndTo;
7
8 // 是否线程暂停
9 bool IsThreadPaused;
10
11 ManualResetEvent CancelEvent = new ManualResetEvent(false);
12 Thread MyThread;
13
14 /// <summary>
15 /// 委托的消息事件
16 /// </summary>
17 /// <param name="nProgress">进度值</param>
18 private void MessageHandler(int nProgress)
19 {
20 lblThreadStatus.Text = "处理: " + Convert.ToString(nProgress);
21 progressBarThread.Value = nProgress;
22
23 if (nProgress == progressBarThread.Maximum)
24 {
25 MessageBox.Show("Completed");
26 this.btnTread.Enabled = true;
27 }
28 }
29
30 /// <summary>
31 /// Handles the Click event of the btnTread control.
32 /// </summary>
33 /// <param name="sender">The source of the event.</param>
34 /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
35 private void btnTread_Click(object sender, EventArgs e)
36 {
37 TheDelegate = MessageHandler;
38
39 StartFrom = Convert.ToInt32(txtStart.Text);
40 EndTo = Convert.ToInt32(txtEnd.Text);
41
42 progressBarThread.Minimum = StartFrom;
43 progressBarThread.Maximum = EndTo;
44
45 btnTread.Enabled = false;
46
47 IsThreadPaused = false;
48 MyThread = new Thread(ProcessRoutine);
49 MyThread.Start();
50 }
51
52 /// <summary>
53 /// Processes the routine.
54 /// </summary>
55 private void ProcessRoutine()
56 {
57 for (int nValue = StartFrom; nValue <= EndTo; nValue++)
58 {
59 // 判断是否取消
60 if (CancelEvent.WaitOne(0, false) == true)
61 {
62 return;
63 }
64 this.BeginInvoke(this.TheDelegate, nValue);
65 Thread.Sleep(200);
66 }
67 }
68
69 /// <summary>
70 /// Handles the Click event of the btnCancelThread control.
71 /// </summary>
72 /// <param name="sender">The source of the event.</param>
73 /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
74 private void btnCancelThread_Click(object sender, EventArgs e)
75 {
76 btnCancelThread.Enabled = false;
77 btnPauseThread.Enabled = false;
78
79 CancelEvent.Set();
80 MyThread.Join();
81 }
82
83 /// <summary>
84 /// Handles the Click event of the btnPauseThread control.
85 /// </summary>
86 /// <param name="sender">The source of the event.</param>
87 /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
88 private void btnPauseThread_Click(object sender, EventArgs e)
89 {
90 // Bad approach!
91 if (!IsThreadPaused)
92 {
93 IsThreadPaused = true;
94 MyThread.Suspend();
95 btnPauseThread.Text = "Resume Thread";
96
97 // Disallow Cancel
98 btnCancelThread.Enabled = false;
99 }
100 else
101 {
102 IsThreadPaused = false;
103 MyThread.Resume();
104 btnPauseThread.Text = "Pause Thread";
105 btnCancelThread.Enabled = true;
106 }
107 }
108
比较起来,两个是完全相同的,对于Thread来说,灵活性就比较好了,BackgroundWorker的使用就相对来说简单了。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· [AI/GPT/综述] AI Agent的设计模式综述