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
。