当一群背景工作者完成时如何知道

时间:2015-01-09 23:52:46

标签: c# .net asynchronous

我有一个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会运行,因此我不确定该怎么做。

3 个答案:

答案 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
        }
    }