如何在有backgroundWorker的过程中停止执行
How to stop the implementation during the process with backgroundWorker
因此此代码采用具有随机起始编号的递增数字流的值。如果 start1 值大于 start2 我想显示与文本框对应的行,否则显示另一行。
问题是在不满足给定的循环次数之前我无法停止程序。按钮只是在植入过程中挂起。我了解发生这种情况的原因是循环。现在我试图用 backgroundWorker 停止它,但我得到了相同的结果,取消按钮以相同的方式挂起。
我想与位于 backgroundWorker1_ProgressChanged 内的 backgroundWorker 一起使用的代码。我真的不太明白这里发生了什么。也许你能帮我找出我做错了什么:
using System;
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;
namespace XX_8_0
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.WorkerSupportsCancellation = true;
}
private void startAsyncButton_Click(object sender, EventArgs e)
{
if (backgroundWorker1.IsBusy != true)
{
backgroundWorker1.RunWorkerAsync();
}
}
private void cancelAsyncButton_Click(object sender, EventArgs e)
{
if (backgroundWorker1.WorkerSupportsCancellation == true)
{
backgroundWorker1.CancelAsync();
}
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
for (int i = 1; i <= 10; i++)
{
if (worker.CancellationPending == true)
{
e.Cancel = true;
break;
}
else
{
System.Threading.Thread.Sleep(500);
worker.ReportProgress(i * 10);
}
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
var random = new Random();
var start1 = random.Next(0, 100);
var start2 = random.Next(0, 100);
var incrementor1 = start1 > 50 ? -1 : 1;
var incrementor2 = start2 > 50 ? -1 : 1;
var cV1 = start1;
var cV2 = start2;
for (var i = 0; i < 1000; i++)
{
if (cV1 == 101) incrementor1 = -1;
if (cV1 == 0) incrementor1 = 1;
if (cV2 == 101) incrementor2 = -1;
if (cV2 == 0) incrementor2 = 1;
if (cV1 > cV2)
{
textBox1.AppendText("ID: (" + i + ") CV1: (1): [" + cV1 + "] CV2: (0) [" + cV2 + "]\n");
}
else
{
textBox1.AppendText("ID: (" + i + ") CV1: (0): [" + cV1 + "] CV2: (1) [" + cV2 + "]\n");
}
cV1 += incrementor1;
cV2 += incrementor2;
}
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled == true)
{
resultLabel.Text = "Canceled!";
}
else if (e.Error != null)
{
resultLabel.Text = "Error: " + e.Error.Message;
}
else
{
resultLabel.Text = "Done!";
}
}
}
}
注意:我认为您的示例可能不是 BackgroundWorker
可以做什么的真正好示例。本质上你的代码只是休眠了一会儿然后报告进度,在另一个线程中几乎没有用。
您的 backgroundWorker1_ProgressChanged
添加 1000 textBox1.AppendText()
非常繁重,因此可能需要一些时间。
Button just hangs during implantation. I understand that the reason why this happens is a loop.
当您考虑 backgroundWorker1_ProgressChanged
在 UI 线程上执行时,无论您在 取消 上进行多少次点击都不会被处理,直到 backgroundWorker1_ProgressChanged
returns。所有 UI 处理都必须由 UI 线程完成。应该指出的是,后台工作线程在此期间也被挂起,不幸的是,它是测试取消测试的代码的唯一部分。即使 ReportProgress
是异步的,你仍然需要 UI 线程来处理取消按钮点击事件并将工作标记为 CancellationPending
.
我建议您不要在 backgroundWorker1_ProgressChanged
中一口气报告那么多,或者可以考虑报告向 textBox1
中添加项目作为 批量 。
这样您就不会淹没您的消息泵并且您的应用程序会更加响应。
将您的 backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
更改为使用 批次 作为:
var builder = new StringBuilder();
for (var i = 0; i < 1000; i++)
{
if (cV1 == 101) incrementor1 = -1;
if (cV1 == 0) incrementor1 = 1;
if (cV2 == 101) incrementor2 = -1;
if (cV2 == 0) incrementor2 = 1;
if (cV1 > cV2)
{
builder.Append("ID: (" + i + ") CV1: (1): [" + cV1 + "] CV2: (0) [" + cV2 + "]\n");
}
else
{
builder.Append("ID: (" + i + ") CV1: (0): [" + cV1 + "] CV2: (1) [" + cV2 + "]\n");
}
cV1 += incrementor1;
cV2 += incrementor2;
}
textbox1.AppendText(builder.ToString());
由于您的 ProgressChanged
处理程序非常忙于每次 ReportProgress
调用更新 UI 大约 1000 次,它将使用所有 UI 线程 CPU 时间该线程将永远无法处理“取消”按钮,因为它已经太忙了。
鉴于您使用 BackgroundWorker
,您确实应该在 DoWork
处理程序中移动大部分 ProgressChanged
,并在后台线程中删除休眠。
顺便说一下,你用的BackgroundWorker
没有任何意义。 UI 线程应该做的越少越好,后台线程应该做的越多越好。在你的情况下,在后台线程中休眠是没有意义的,因为后台工作不依赖于经过的时间。
移动代码后,您需要将数据发送回 UI 线程。但这很容易,因为 ReportProgress
的重载允许将任何 .NET 对象传递给 UI 线程(假设后台工作程序是从 UI 线程创建的,通常是案子)。另一方面,您只需将用户数据转换为适当的类型,并使用该信息将适当的文本附加到文本框。
通过改进代码,您应该能够更快地处理该数据。顺便说一下,StringBuilder
也应该用于构建字符串。事实上,它应该对 UI 性能产生巨大影响,因为您更新 UI 文本的频率减少了 1000 次。
因此此代码采用具有随机起始编号的递增数字流的值。如果 start1 值大于 start2 我想显示与文本框对应的行,否则显示另一行。
问题是在不满足给定的循环次数之前我无法停止程序。按钮只是在植入过程中挂起。我了解发生这种情况的原因是循环。现在我试图用 backgroundWorker 停止它,但我得到了相同的结果,取消按钮以相同的方式挂起。
我想与位于 backgroundWorker1_ProgressChanged 内的 backgroundWorker 一起使用的代码。我真的不太明白这里发生了什么。也许你能帮我找出我做错了什么:
using System;
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;
namespace XX_8_0
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.WorkerSupportsCancellation = true;
}
private void startAsyncButton_Click(object sender, EventArgs e)
{
if (backgroundWorker1.IsBusy != true)
{
backgroundWorker1.RunWorkerAsync();
}
}
private void cancelAsyncButton_Click(object sender, EventArgs e)
{
if (backgroundWorker1.WorkerSupportsCancellation == true)
{
backgroundWorker1.CancelAsync();
}
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
for (int i = 1; i <= 10; i++)
{
if (worker.CancellationPending == true)
{
e.Cancel = true;
break;
}
else
{
System.Threading.Thread.Sleep(500);
worker.ReportProgress(i * 10);
}
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
var random = new Random();
var start1 = random.Next(0, 100);
var start2 = random.Next(0, 100);
var incrementor1 = start1 > 50 ? -1 : 1;
var incrementor2 = start2 > 50 ? -1 : 1;
var cV1 = start1;
var cV2 = start2;
for (var i = 0; i < 1000; i++)
{
if (cV1 == 101) incrementor1 = -1;
if (cV1 == 0) incrementor1 = 1;
if (cV2 == 101) incrementor2 = -1;
if (cV2 == 0) incrementor2 = 1;
if (cV1 > cV2)
{
textBox1.AppendText("ID: (" + i + ") CV1: (1): [" + cV1 + "] CV2: (0) [" + cV2 + "]\n");
}
else
{
textBox1.AppendText("ID: (" + i + ") CV1: (0): [" + cV1 + "] CV2: (1) [" + cV2 + "]\n");
}
cV1 += incrementor1;
cV2 += incrementor2;
}
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled == true)
{
resultLabel.Text = "Canceled!";
}
else if (e.Error != null)
{
resultLabel.Text = "Error: " + e.Error.Message;
}
else
{
resultLabel.Text = "Done!";
}
}
}
}
注意:我认为您的示例可能不是 BackgroundWorker
可以做什么的真正好示例。本质上你的代码只是休眠了一会儿然后报告进度,在另一个线程中几乎没有用。
您的 backgroundWorker1_ProgressChanged
添加 1000 textBox1.AppendText()
非常繁重,因此可能需要一些时间。
Button just hangs during implantation. I understand that the reason why this happens is a loop.
当您考虑 backgroundWorker1_ProgressChanged
在 UI 线程上执行时,无论您在 取消 上进行多少次点击都不会被处理,直到 backgroundWorker1_ProgressChanged
returns。所有 UI 处理都必须由 UI 线程完成。应该指出的是,后台工作线程在此期间也被挂起,不幸的是,它是测试取消测试的代码的唯一部分。即使 ReportProgress
是异步的,你仍然需要 UI 线程来处理取消按钮点击事件并将工作标记为 CancellationPending
.
我建议您不要在 backgroundWorker1_ProgressChanged
中一口气报告那么多,或者可以考虑报告向 textBox1
中添加项目作为 批量 。
这样您就不会淹没您的消息泵并且您的应用程序会更加响应。
将您的 backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
更改为使用 批次 作为:
var builder = new StringBuilder();
for (var i = 0; i < 1000; i++)
{
if (cV1 == 101) incrementor1 = -1;
if (cV1 == 0) incrementor1 = 1;
if (cV2 == 101) incrementor2 = -1;
if (cV2 == 0) incrementor2 = 1;
if (cV1 > cV2)
{
builder.Append("ID: (" + i + ") CV1: (1): [" + cV1 + "] CV2: (0) [" + cV2 + "]\n");
}
else
{
builder.Append("ID: (" + i + ") CV1: (0): [" + cV1 + "] CV2: (1) [" + cV2 + "]\n");
}
cV1 += incrementor1;
cV2 += incrementor2;
}
textbox1.AppendText(builder.ToString());
由于您的 ProgressChanged
处理程序非常忙于每次 ReportProgress
调用更新 UI 大约 1000 次,它将使用所有 UI 线程 CPU 时间该线程将永远无法处理“取消”按钮,因为它已经太忙了。
鉴于您使用 BackgroundWorker
,您确实应该在 DoWork
处理程序中移动大部分 ProgressChanged
,并在后台线程中删除休眠。
顺便说一下,你用的BackgroundWorker
没有任何意义。 UI 线程应该做的越少越好,后台线程应该做的越多越好。在你的情况下,在后台线程中休眠是没有意义的,因为后台工作不依赖于经过的时间。
移动代码后,您需要将数据发送回 UI 线程。但这很容易,因为 ReportProgress
的重载允许将任何 .NET 对象传递给 UI 线程(假设后台工作程序是从 UI 线程创建的,通常是案子)。另一方面,您只需将用户数据转换为适当的类型,并使用该信息将适当的文本附加到文本框。
通过改进代码,您应该能够更快地处理该数据。顺便说一下,StringBuilder
也应该用于构建字符串。事实上,它应该对 UI 性能产生巨大影响,因为您更新 UI 文本的频率减少了 1000 次。