如何知道一组 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
        }
    }