如何知道一组 BackgroundWorker 何时完成
How To Know When A Group Of BackgroundWorkers Are Done
我有一个 URL 的列表,并且为每个 URL 创建一个 BackgroundWorker 来处理下载数据和更新其各自的 ProgressBar。
我的问题是如何确定所有下载何时完成?截至目前,我只能找出每个 BackgroundWorker 何时单独完成而不是作为一个组完成。
for (int i = 0; i < videos.Count; i++)
{
int index = i;
string path = Path.Combine(Settings.Default.DownloadLocation,
videos[index].Title + videos[index].AudioExtension);
BackgroundWorker worker = new BackgroundWorker
{
WorkerReportsProgress = true,
WorkerSupportsCancellation = false
};
worker.DoWork += delegate
{
AudioDownloader audioDownloader = new AudioDownloader(videos[index], path);
audioDownloader.AudioExtractionProgressChanged += (obj, args) =>
{
int progress = (int)Math.Round(85 + args.ProgressPercentage * 0.15);
worker.ReportProgress(progress);
};
audioDownloader.DownloadProgressChanged += (obj, args) =>
{
int progress = (int)Math.Round(args.ProgressPercentage * 0.85);
worker.ReportProgress(progress);
};
audioDownloader.Execute();
};
worker.ProgressChanged += (obj, args) =>
{
progressi[index].Value = args.ProgressPercentage;
};
worker.RunWorkerCompleted += delegate
{
Notify(videos[index].Title + " is finished downloading.");
};
worker.RunWorkerAsync();
}
我正在考虑做这样的事情:
Task[] downloadTasks = new Task[videos.Count];
for (int i = 0; i < videos.Count; i++)
{
int index = i;
downloadTasks[index] = Task.Factory.StartNew(() =>
{
// Create BackgroundWorker and run it
});
}
Task.Factory.ContinueWhenAll(downloadTasks, (tasks) =>
{
// All the downloads are complete!
});
但是 ContinueWhenAll 在下载实际完成之前运行,所以我不确定该怎么做。
当你这样做的时候
for (int i = 0; i < videos.Count; i++)
{
int index = i;
downloadTasks[index] = Task.Factory.StartNew(() =>
{
// Create BackgroundWorker and run it
});
}
你创建了一些后台工作者并告诉他们在另一个线程中做一些事情。所以在告诉他们完成他们的工作之后,你的任务的工作就完成了,所以所有的(任务)都会在一瞬间完成并且
Task.Factory.ContinueWhenAll(downloadTasks, (tasks) =>
{
// All the downloads are complete!
});
检查是否所有任务都已完成工作?答案是:是的!他们都创建了一个后台工作人员并告诉他们该做什么。
您可以使用某种标志,为每个后台工作人员分配一个 ID,并在完成工作后在数组中设置一个布尔值。检查他们是否都完成了他们的工作,然后继续。您可以在 Notify
方法中执行此操作。检查所有标志是否为真,然后在那里做你想做的。
使用 BackgroundWorker 自 .Net 4.5 以来通过任务返回异步方法有些过时。这很好地解释了为什么 here.
在您的用例中,您可能会得到像这样简单的东西:
public async Task DownloadTask()
{
Task[] tasks = new Task[2];
tasks[0] = DoSomeStuff();
tasks[1] = DoSomeStuff();
await Task.WhenAll(tasks);
}
另一个简单的解决方法 - 使用一个计数器来跟踪所有后台工作人员。
int counter = 0;
在每个backgroundworker的DoWork中:
private void bwDoWork(object sender, DoWorkEventArgs e)
{
Interlocked.Increment(ref counter);
//do other stuff
}
并且在每个 RunWorkerCompleted 中,递减计数器并检查是否为零,这告诉您所有后台工作程序都已完成
private void bwRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Interlocked.Decrement(ref counter);
if (counter == 0)
{
//All backgroundworkers are done, so do something
}
}
我有一个 URL 的列表,并且为每个 URL 创建一个 BackgroundWorker 来处理下载数据和更新其各自的 ProgressBar。
我的问题是如何确定所有下载何时完成?截至目前,我只能找出每个 BackgroundWorker 何时单独完成而不是作为一个组完成。
for (int i = 0; i < videos.Count; i++)
{
int index = i;
string path = Path.Combine(Settings.Default.DownloadLocation,
videos[index].Title + videos[index].AudioExtension);
BackgroundWorker worker = new BackgroundWorker
{
WorkerReportsProgress = true,
WorkerSupportsCancellation = false
};
worker.DoWork += delegate
{
AudioDownloader audioDownloader = new AudioDownloader(videos[index], path);
audioDownloader.AudioExtractionProgressChanged += (obj, args) =>
{
int progress = (int)Math.Round(85 + args.ProgressPercentage * 0.15);
worker.ReportProgress(progress);
};
audioDownloader.DownloadProgressChanged += (obj, args) =>
{
int progress = (int)Math.Round(args.ProgressPercentage * 0.85);
worker.ReportProgress(progress);
};
audioDownloader.Execute();
};
worker.ProgressChanged += (obj, args) =>
{
progressi[index].Value = args.ProgressPercentage;
};
worker.RunWorkerCompleted += delegate
{
Notify(videos[index].Title + " is finished downloading.");
};
worker.RunWorkerAsync();
}
我正在考虑做这样的事情:
Task[] downloadTasks = new Task[videos.Count];
for (int i = 0; i < videos.Count; i++)
{
int index = i;
downloadTasks[index] = Task.Factory.StartNew(() =>
{
// Create BackgroundWorker and run it
});
}
Task.Factory.ContinueWhenAll(downloadTasks, (tasks) =>
{
// All the downloads are complete!
});
但是 ContinueWhenAll 在下载实际完成之前运行,所以我不确定该怎么做。
当你这样做的时候
for (int i = 0; i < videos.Count; i++)
{
int index = i;
downloadTasks[index] = Task.Factory.StartNew(() =>
{
// Create BackgroundWorker and run it
});
}
你创建了一些后台工作者并告诉他们在另一个线程中做一些事情。所以在告诉他们完成他们的工作之后,你的任务的工作就完成了,所以所有的(任务)都会在一瞬间完成并且
Task.Factory.ContinueWhenAll(downloadTasks, (tasks) =>
{
// All the downloads are complete!
});
检查是否所有任务都已完成工作?答案是:是的!他们都创建了一个后台工作人员并告诉他们该做什么。
您可以使用某种标志,为每个后台工作人员分配一个 ID,并在完成工作后在数组中设置一个布尔值。检查他们是否都完成了他们的工作,然后继续。您可以在 Notify
方法中执行此操作。检查所有标志是否为真,然后在那里做你想做的。
使用 BackgroundWorker 自 .Net 4.5 以来通过任务返回异步方法有些过时。这很好地解释了为什么 here.
在您的用例中,您可能会得到像这样简单的东西:
public async Task DownloadTask()
{
Task[] tasks = new Task[2];
tasks[0] = DoSomeStuff();
tasks[1] = DoSomeStuff();
await Task.WhenAll(tasks);
}
另一个简单的解决方法 - 使用一个计数器来跟踪所有后台工作人员。
int counter = 0;
在每个backgroundworker的DoWork中:
private void bwDoWork(object sender, DoWorkEventArgs e)
{
Interlocked.Increment(ref counter);
//do other stuff
}
并且在每个 RunWorkerCompleted 中,递减计数器并检查是否为零,这告诉您所有后台工作程序都已完成
private void bwRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Interlocked.Decrement(ref counter);
if (counter == 0)
{
//All backgroundworkers are done, so do something
}
}