C# 正在等待来自多个对象的任务

C# 正在等待来自多个对象的任务,c#,async-await,.net-core,task,task-parallel-library,C#,Async Await,.net Core,Task,Task Parallel Library,我有一个使用MEF加载插件的应用程序。所有这些插件都符合以下接口: public interface IPlugin { Task Start(); } 所有方法都实现为async:public async Task Start() 当应用程序运行时,所有插件都有一个IEnumerable属性。问题基本上是如何并行运行所有的Start()方法并等待所有方法完成 我知道关于Parallel.ForEach(plugins,plugin=>plugin.Start()),但这不是等待的,在

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

public interface IPlugin {
    Task Start();
}
所有方法都实现为
async
public async Task Start()

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

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

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

我如何才能做到这一点?

您可以做到:

var tasks = new List<Task>();
foreach(var plugin in plugins) 
{
   var task = plugin.Start();
   tasks.Add(task);
}
await Task.WhenAll(tasks); 
var tasks=newlist();
foreach(插件中的var插件)
{
var task=plugin.Start();
任务。添加(任务);
}
等待任务。何时(任务);
您可以执行以下操作:

var tasks = new List<Task>();
foreach(var plugin in plugins) 
{
   var task = plugin.Start();
   tasks.Add(task);
}
await Task.WhenAll(tasks); 
var tasks=newlist();
foreach(插件中的var插件)
{
var task=plugin.Start();
任务。添加(任务);
}
等待任务。何时(任务);

如您所见,
Start
方法返回一个
任务
。我会定义一个插件加载任务列表,并在每个任务完成后检查
Task.whalll
。在此之后,您可以假设所有
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
列出插件=。。。
var pluginsLoadingTasks=新列表();
foreach(插件中的var插件)
{
pluginLoadingTasks.Add(plugin.Start());
}
//不必检查pluginsLoadingTasks是否为空,
//因为在这种情况下WhenAll不会抛出异常
等待任务。WhenAll(插件加载任务);
//您可以假定所有启动方法都已完成

我建议您在
Task.whalll
Parallel.ForEach
构造之间进行选择。

如您所见
Start
方法返回一个
Task
。我会定义一个插件加载任务列表,并在每个任务完成后检查
Task.whalll
。在此之后,您可以假设所有
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
列出插件=。。。
var pluginsLoadingTasks=新列表();
foreach(插件中的var插件)
{
pluginLoadingTasks.Add(plugin.Start());
}
//不必检查pluginsLoadingTasks是否为空,
//因为在这种情况下WhenAll不会抛出异常
等待任务。WhenAll(插件加载任务);
//您可以假定所有启动方法都已完成

我建议您在所有的任务和并行的任务之间进行转换。ForEach构造。

下面是一行代码:

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

插件将异步运行,但不会并行运行。如果出于某种原因想显式地将插件分派到线程池,可以添加
任务。使用
async
lambda运行
,然后选择
,,下面是一行代码:

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

插件将异步运行,但不会并行运行。如果出于某种原因要显式地将插件分派到线程池,可以添加
任务。使用
async
lambda运行
选择
,您可以使用Microsoft的反应式框架来确保这是可以等待的,以异步和并行方式进行

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

您可以使用Microsoft的反应式框架来确保这是可以等待的、异步和并行进行的

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


我最讨厌的是
if(collection.Count>0)
-使用
if(collection.Any())
。你不在乎有多少东西,只要‘有吗?’。@Neil,很好的建议!我总是忘记在这种情况下,
Any()
更有效。:)或者你可以ommit
Any
检查
WhenAll
可以处理零任务。你可能是指
Task.WhenAll
,而不是
任务。WhenAll
@Sergey.quixoticaxis.Ivanov,我不知道你可以传递一个空集合给它,所以谢谢你的建议。我最讨厌的是
如果(collection.Count>0)
-使用
if(collection.Any())
。你不在乎有多少东西,只要‘有吗?’。@Neil,很好的建议!我总是忘记在这种情况下,
Any()
更有效。:)或者你可以使用ommit
Any
检查
WhenAll
可以处理零任务。你可能是指
Task.WhenAll
,而不是
任务。WhenAll
@Sergey.quixoticaxis.Ivanov,我不知道你可以向它传递一个空集合,所以谢谢你的建议。你的答案和弗兰克的建议有什么不同?你的答案和弗兰克的建议有什么不同?狗娘养的,这段时间它一直盯着我的脸看!您是否愿意详细说明“插件将异步运行,但不是并行运行”?您可以输出
CurrentThread
的id,您将看到插件至少在单个线程上启动。这里有一篇关于它的好文章:@Sergey.quixoticaxis.Ivanov为了并行运行,使用
AsParallel()
(如
plugins.AsParallel()。选择(p=>p.Start())
)而不是
Task.Run
)可能不是更好吗?看,我怀疑这会有什么不同。此外,我不确定插件是否能从并行查询中的“分块”工作中获得任何价值。应该测量一下irl,什么对这个案子更有利。狗娘养的,它一直盯着我的脸看!您是否愿意详细说明“插件将异步运行,但不是并行运行”?您可以输出
CurrentThread
的id,您将看到插件至少在单个线程上启动。这里有一篇关于它的好文章:@Sergey.quixoticaxis.Ivanov为了并行运行,使用
AsParallel()
(如
plugins.AsParallel()。选择(p=>p.Start())
)而不是
Task.Run
)可能不是更好吗?看,我怀疑这会有什么不同。此外,我也不确定插件是否能获得成功