如何在控制台应用程序中从 Task.WaitAll()获取返回值?

我正在使用一个控制台应用程序作为一个概念和新的需要得到一个异步返回值的证明。

我发现我需要在我的 main 方法中使用 Task.WaitAll()来避免需要一个异步的“ main ()”方法,这是非法的。

现在我只能试图找出一个允许我使用泛型的重载,或者只是返回一个我可以强制转换但是在 Main ()中的对象。

67099 次浏览

不能从 Task.WaitAll获得返回值。您只能使用它等待多个任务完成,然后从任务本身获取返回值。

var task1 = GetAsync(1);
var task2 = GetAsync(2);
Task.WaitAll(task1, task2);
var result1 = task1.Result;
var result2 = task2.Result;

如果只有一个 Task,只需使用 Result属性。如果任务尚未完成,它将返回您的值并阻止调用线程:

var task = GetAsync(3);
var result = task.Result;

一般来说,对异步任务进行同步等待(阻塞)并不是一个好主意,但我想对于 POC 来说,这是可以接受的。

对于最佳实践,使用新的异步方法来做事情。 而不是

  • 使用 await Task.WhenAll
  • 使用 await Task.WhenAny

上面的代码可以写成:

var task1 = GetAsync(1);
var task2 = GetAsync(2);
var results = await Task.WhenAll(task1, task2);
var result1 = results[0];
var result2 = results[1];

根据上下文和你的需要,你可以使用不同的方法,但是我尝试了 i3arnon 和 alltej 的答案,在调试中我发现它们都有相同的问题... ... 我在自己编写的控制台应用程序中运行了这两个代码样本。我在代码中设置了一个断点,发现在用 Task.WaitAllTask.WhenAll执行的行上。当我检查这些任务时,我发现它们已经运行了-任务属性 Status = ran to completion。事实上,我能够完全删除 Task.行代码,并仍然分配变量值,所以它是无用的。

我发现这是一个非常困难的任务,真正使这种操作运行所需要的,并得到所需的返回值。以下是我的想法:

Task[] taskArray = {
Task.Factory.StartNew(() => ExecuteConcurrentTasks(1).Result),
Task.Factory.StartNew(() => ExecuteConcurrentTasks(2).Result)
};
Task.WaitAll(taskArray);
var s = ((Task<string>)taskArray[0]).Result;

这是一个简单的例子,其中创建了一个任务数组,然后使用 Task.WaitAll同时执行这两个任务,然后在最后一行我将演示如何访问第一个任务返回的值。

下面是具有更多上下文和更多数据的代码:

private static async void MyAsyncMethod()
{
Task[] taskArray = {
Task.Factory.StartNew(() => ExecuteConcurrentTasks(1).Result),
Task.Factory.StartNew(() => ExecuteConcurrentTasks(2).Result),
Task.Factory.StartNew(() => ExecuteConcurrentTasks(3).Result),
Task.Factory.StartNew(() => ExecuteConcurrentTasks(4).Result)
};
Task.WaitAll(taskArray);
string s1 = ((Task<string>)taskArray[0]).Result;
string s2 = ((Task<string>)taskArray[1]).Result;
string s3 = ((Task<string>)taskArray[2]).Result;
string s4 = ((Task<string>)taskArray[3]).Result;
}






private static async Task<string> ExecuteConcurrentTasks(int passedInt)
{
string s = "Result: " + passedInt.ToString();


if (passedInt == 4)
{
Console.WriteLine(s);
}
else if (passedInt == 3)
{
Console.WriteLine(s);
}
else if (passedInt == 2)
{
Console.WriteLine(s);
}
else if (passedInt == 1)
{
Console.WriteLine(s);
}


return s;
}

以下是输出结果:

output


更新:

通过与其他一些开发人员合作,我对这些方法有了更多的了解。我现在的理解是,.WaitAll将阻止 程序的其他部分中的执行,如果您不仅仅运行一个非常简单的程序,那么这就是一个问题。同样,.WhenAll并不意味着任务不会执行,直到该行和所有在该行开始异步执行,它只是意味着该块中的代码不会继续超过该点,除非所有指定的任务已经完成运行。