报告进度不调用进度在 c# 中更改了任务
本文关键字:任务 调用 报告 | 更新日期: 2024-09-21 03:45:11
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
int currentProgress=-1;
while (currentProgress<length)
{
currentProgress=Worker.progress;
backgroundWorker1.ReportProgress(currentProgress);
Thread.Sleep(500);
length = Worker.UrlList.Count;
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
int ix = e.ProgressPercentage;
progressBar1.Value = ix;
lblText.Text =ix+" %";
}
我编写了一个程序,通过读取一个文件来下载页面源代码,其中包含大约 1000 个 URL。 所以我使用任务异步下载页面。 这里Worker.progress
是当前执行的 URL 量。 尽管调试器命中backgroundWorker1.ReportProgress(currentProgress);
但它永远不会进入backgroundWorker1_ProgressChanged
。
private void StartButton_Click(object sender, EventArgs e)
{
t.makeUrlList(inputFile);
backgroundWorker1 = new BackgroundWorker();
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.DoWork += backgroundWorker1_DoWork;
backgroundWorker1.ProgressChanged += backgroundWorker1_ProgressChanged;
backgroundWorker1.RunWorkerAsync();
t.RunTasks();
Application.Exit();
}
后台工作线程在启动按钮单击时初始化...
这是我的任务创建的地方。
public void RunTasks()
{
if (numOfTasks > UrlList.Count)
numOfTasks=UrlList.Count-1;
Task[] t = new Task[numOfTasks];
int j = 0;
while ( j < UrlList.Count-1)
{
for (int i = 0; (i < t.Count())&&(j<UrlList.Count-1); i++)
{
try
{
if (t[i].IsCompleted || t[i].IsCanceled || t[i].IsFaulted)
{
t[i] = Task.Run(() => FindWIN(j));
j++;
progress = j;
}
}
catch (NullReferenceException ex)
{
t[i] = Task.Run(() => FindWIN(j));
j++;
progress = j;
}
}
}
}
如果要 BackgroundWorker 支持更新进度信息,则 WorkerReportsProgress 的值应设置为 true 。如果此属性为 true,则用户代码可以调用 ReportProgress 来启动事件 ProgressChanged 。
后台工作线程初始化:-
backgroundWorker1 = new BackgroundWorker();
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.DoWork+=backgroundWorker1_DoWork;
backgroundWorker1.ProgressChanged+=backgroundWorker1_ProgressChanged;
backgroundWorker1.RunWorkerAsync();
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
int currentProgress = -1;
decimal length=1000;
while (currentProgress < length)
{
currentProgress = Worker.progress;
backgroundWorker1.ReportProgress(currentProgress);
Thread.Sleep(500);
length = Worker.UrlList.Count;
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) {
int ix = e.ProgressPercentage;
progressBar1.Value = ix;
lblText.Text = ix + " %";
}
您应该在初始化阶段将 worker 的 WorkerReportsProgress 属性设置为 true。
请参阅下面的演示代码。这大多未经测试,当然也不是"生产标准",但它应该给你一个良好的开端!
-
它使用
ConcurrentQueue
来保存要处理的 URL 列表。这是线程安全的,使生活更轻松。 -
它具有可配置数量的 url 和任务。最好不要创建 1000 个任务,而是有一个工作项队列和一个较小的任务池,这些任务池将项目从队列中"拉出",直到它为空。这意味着您可以对不同数量的任务进行性能测试,并为您的问题找到最佳值。
-
它在更新进度条时使用 Invoke - 这避免了跨线程异常。
-
没有
BackgroundWorker
- 只有TaskFactory
和Task
public partial class Form1 : Form { private const int UrlCount = 1000; private const int taskCount = 10; private ConcurrentQueue<string> urlList; private List<Task> taskList; public Form1() { InitializeComponent(); } private void ResetQueue() { // fake up a number of strings to process urlList = new ConcurrentQueue<string>(Enumerable.Range(0, UrlCount) .Select(i => "http://www." + Guid.NewGuid().ToString() + ".com")); } private void button1_Click(object sender, EventArgs e) { ResetQueue(); var taskFactory = new TaskFactory(); // start a bunch of tasks taskList = Enumerable.Range(0, taskCount).Select(i => taskFactory.StartNew(() => ProcessUrl())) .ToList(); } void ProcessUrl() { string current; // keep grabbing items till the queue is empty while (urlList.TryDequeue(out current)) { // run your code FindWIN(current); // invoke here to avoid cross thread issues Invoke((Action)(() => UpdateProgress())); } } void FindWIN(string url) { // your code here // as a demo, sleep a sort-of-random time between 0 and 100 ms Thread.Sleep(Math.Abs(url.GetHashCode()) % 100); } void UpdateProgress() { // work out what percentage of the queue is processed progressBar1.Value = (int)(100 - ((double)urlList.Count * 100.0 / UrlCount)); } }