我有一个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会运行,因此我不确定该怎么做。
答案 0 :(得分:2)
当你这样做时
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
方法执行此操作。检查所有标志是否都为真,然后在那里做你想做的事。
答案 1 :(得分:1)
使用 BackgroundWorker 从.Net 4.5开始,通过任务返回异步方法有点过时了。这很好地解释了为什么here。
在您的使用案例中,您最终可能会遇到以下简单的事情:
public async Task DownloadTask()
{
Task[] tasks = new Task[2];
tasks[0] = DoSomeStuff();
tasks[1] = DoSomeStuff();
await Task.WhenAll(tasks);
}
答案 2 :(得分:1)
另一个简单的解决方法 - 使用计数器跟踪所有背景工作者。
int counter = 0;
在每个背景工作者的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
}
}