C# 如何从WhenAll(任务数组)中获得结果

C# 如何从WhenAll(任务数组)中获得结果,c#,multithreading,C#,Multithreading,我有以下代码 var tasks=new[] { Task.Factory.StartNew(()=>GetSomething1()), Task.Factory.StartNew(()=>GetSomething2()), Task.Factory.StartNew(()=>GetSomething3()) }; var things=Task.WhenAll(任务); 如何分别从所有三个任务中获取结果并打印它们?一种方法是让每个任务负责存储自己的结果,然后您所要做的就是等待任务集合。请注意

我有以下代码

var tasks=new[]
{
Task.Factory.StartNew(()=>GetSomething1()),
Task.Factory.StartNew(()=>GetSomething2()),
Task.Factory.StartNew(()=>GetSomething3())
};
var things=Task.WhenAll(任务);

如何分别从所有三个任务中获取结果并打印它们?

一种方法是让每个
任务负责存储自己的结果,然后您所要做的就是等待任务集合。请注意,您必须使用
wait
使
WhenAll()
执行传递给它的任务

var results = new int[3];

var tasks = new[] {
    Task.Factory.StartNew(() => results[0] = GetSomething1()), 
    Task.Factory.StartNew(() => results[1] = GetSomething2()), 
    Task.Factory.StartNew(() => results[2] = GetSomething3())
};

await Task.WhenAll(tasks);

Console.WriteLine(results[0]);
Console.WriteLine(results[1]);
Console.WriteLine(results[2]);
工作演示:


请注意,您可能需要小心使用
列表而不是数组,然后调用
List.Add(result)
,因为无法保证任务的执行顺序或完成时间。

您应该使用
async..wait
模式和
when
,例如

  private async Task MyExecution() {
    var tasks = new[] {
      //TODO: Task.Run is a better option than Task.Factory.StartNew
      Task.Factory.StartNew(() => GetSomething1()),
      Task.Factory.StartNew(() => GetSomething2()),
      Task.Factory.StartNew(() => GetSomething3())
    };

    // Await until all tasks are completed 
    await Task.WhenAll(tasks);

    // Since all tasks are completed, we can (safely) query for their `Result`s:
    var things = tasks
      .Select(task => task.Result) // or task => await task
      .ToArray();

    // Let's print the things
    for (int i = 0; i < things.Length; ++i) 
      Console.WriteLine($"Task #{i + 1} returned {things[i]}");

    ... 
  }
private异步任务MyExecution(){
var tasks=new[]{
//TODO:Task.Run是比Task.Factory.StartNew更好的选项
Task.Factory.StartNew(()=>GetSomething1()),
Task.Factory.StartNew(()=>GetSomething2()),
Task.Factory.StartNew(()=>GetSomething3())
};
//等待所有任务完成
等待任务。何时(任务);
//由于所有任务都已完成,我们可以(安全地)查询其“结果”:
变量事物=任务
.Select(task=>task.Result)//或task=>wait task
.ToArray();
//让我们把东西打印出来
for(int i=0;i
为了单独获得结果,您有多种方法,我可以这样做:

var task1  = GetSomething1();
var task2  = GetSomething2();
var task3  = GetSomething3();

// your method will continue when everything's completed, but you won't tie up a thread to just hang around until that time.
await Task.WhenAll(task1, task2, task3);

var result1 = await task1;
var result2 = await task2;
var result3 = await task3;

您是否考虑过实际使用异步函数?然后,您就有了一系列具有结果的任务,并避免了
Task.Factory.StartNew
的高度不可预测的行为

private异步任务MyExecution()
{
var tasks=new[]{
GetSomething1(),
GetSomething2(),
GetSomething3()
};
//等待所有任务完成
等待任务。何时(任务);
foreach(任务中的var t){
//t、 结果是可用的
}
}
公共静态异步任务GetSomething1(){return 1;}
公共静态异步任务GetSomething2(){return 2;}
公共静态异步任务GetSomething3(){return 3;}

在这里摆弄:

如果
Get..
方法都是异步的(返回自己的
Task
s),请查看这里,您不需要
.StartNew
。如果它们都是同步的,它们的数目可以是可变的(基于其他集合),考虑使用<代码>枚举。AsParallel < /COD>(PLIQ)或<代码>并行。对于每个[/]代码>并行化工作,而不是将它们打包为任务。@ DmitryBychenko,沿着正确的路径,但是如果在每个任务之后立即使用
Result
,那么对
whalll
的调用是多余的。
List.Add
的真正问题不在于顺序,而在于它不是线程安全的。您需要显式锁或类似于
ConcurrentBag
的东西来解决这个问题。然而,到那时,这样的方法可能不必要地复杂,只有在每个任务的结果数量可变时才值得考虑。否则,没有真正的理由不使用这样一个事实,即任务具有对结果的内置支持(正如在其他答案中使用的那样)。那些“高度不可预测的行为”会是什么?包装同步代码有它的问题,但这些问题并不特定于
StartNew
。举例来说,您提供的
async
方法本身并不是异步的,可能会误导人们认为,启动
async任务
就足以将同步函数转换为异步函数。实际上,在这个特定的代码段中,无论您是否调用过
wait Task.whalll
,结果都是可用的,因为创建数组时代码是同步执行的。@Jeroenmoster不确定您为什么认为原始代码包装了同步代码。可以发现StartNew的一些问题,以及。我提供的异步方法只是一个示例,您是对的:它们是同步运行的。事实上,编译器会对此发出警告。你是对的,这是一个基于以下事实的假设:如果
Get…
方法已经返回
Task
s,那么首先就没有理由将它们插入
.StartNew()
,但OP可能没有意识到这一点。您的答案将通过实际链接到
.StartNew()
中的问题得到改进--我不会将这些陷阱称为“不可预测的”!返回一个
任务
。等待此任务将返回一个包含结果的数组。不需要
.Select.ToArray
之类的东西。如果
GetSomethingX
方法不返回
Task
s(我怀疑它们会返回),那么这不会回答问题,也不会编译。如果他们这样做了,那么调用
whalll
是多余的,特别是因为不清楚
GetSomethingX
是否返回
Task
Task