等待来自多个对象的任务

问题描述 投票:1回答:4

我有一个使用MEF加载插件的应用程序。所有这些插件都符合以下界面:

public interface IPlugin {
    Task Start();
}

所有方法都实现为asyncpublic async Task Start()

当应用程序运行时,我有一个IEnumerable<IPlugin>属性可用于所有插件。问题基本上是我如何并行运行所有Start()方法并等待所有方法完成?

我知道Parallel.ForEach(plugins, plugin => plugin.Start()),但这不是等待的,并且在所有插件启动之前继续执行。

最有希望的解决方案似乎是Task.WhenAll(),但我不知道如何在不添加一些脚手架(这似乎是开销)的情况下将未知的方法列表发送到此。

我怎么能做到这一点?

c# async-await .net-core task task-parallel-library
4个回答
6
投票

这是一个单行:

await Task.WhenAll(plugins.Select(p => p.Start()));

插件将异步运行,但不是并行运行。如果由于某种原因明确地将插件分派给线程池,可以将Task.Runasync lambda一起添加到Select中。


2
投票

你可以做:

var tasks = new List<Task>();
foreach(var plugin in plugins) 
{
   var task = plugin.Start();
   tasks.Add(task);
}
await Task.WhenAll(tasks); 

2
投票

您可以使用Microsoft的Reactive Framework来确保这是可以等待的,异步并行地发生。

await
    plugins
        .ToObservable()
        .SelectMany(plugin => Observable.FromAsync(() => plugin.Start()))
        .ToArray();

0
投票

正如你所看到的Start方法返回一个Task。我将定义一个插件加载任务列表,并在每个任务完成时使用Task.WhenAll进行检查。之后,您可以假设所有Start方法都已返回。

List<IPlugin> plugins = ... 
var pluginsLoadingTasks = new List<Task>();

foreach(var plugin in plugins)
{
    pluginsLoadingTasks.Add(plugin.Start());
}

// It's not necessary to check if pluginsLoadingTasks is empty, 
// because WhenAll won't throw an exception in that case
await Task.WhenAll(pluginsLoadingTasks);
// You can assume all Start methods have completed

我建议你在to read the differencesTask.WhenAll构造之间的Parallel.ForEach

© www.soinside.com 2019 - 2024. All rights reserved.