仍在使用C#进行学习阶段并遇到了一个我需要帮助的问题。考虑以下代码:
private async Task<String> PrintTask()
{
await Task.Delay(3000);
return "Hello";
}
private async void SayHelloTwice()
{
string firstHello = await PrintTask();
string secondHello = await PrintTask();
Console.WriteLine(firstHello);
Console.WriteLine(secondHello);
}
现在SayHelloTwice()需要6秒才能完成。但是,我希望检索任务并行运行,因此只需3秒即可完成。我将如何重构我的代码来实现这一目标?谢谢!
答案 0 :(得分:4)
执行此操作的正确方法(没有死锁风险)是使用Task.WhenAll
private async void SayHelloTwice()
{
string[] results = await Task.WhenAll(
PrintTask(),
PrintTask());
Console.WriteLine(results[0]);
Console.WriteLine(results[1]);
}
图书馆作家经常会努力做出回调&#34;任务中的代码在调用它的原始线程上运行。这通常是因为只能从单个线程访问对象。
使用Task.Result
和Task.WaitAll
之类的阻止调用时,线程暂停(无法执行其他工作),直到Task
完成。
但是如前所述,Task
通常会等待调用线程释放,因此可以用它来完成任务。
所以,在第一种情况下,outter&#34; Task&#34;持有线程,等待完成。
第二种情况,内部&#34;任务&#34;正在等待线程完成。
Ergo将永远不会完成。
答案 1 :(得分:3)
一般来说,你想要的是开始这两项任务,然后等待。 一种直截了当的方式是:
private async void SayHelloTwice()
{
// Start the tasks, don't wait
Task<string> firstHello = PrintTask();
Task<string> secondHello = PrintTask();
// Wait for results
string firstResult = await firstHello;
string secondResult = await secondHello;
// Print results
Console.WriteLine(firstResult);
Console.WriteLine(secondResult);
}
这里发生的是调用PrintTask()
将开始执行该方法,一旦执行到达执行实际异步操作的第一个await
,将返回正在运行的任务并将其分配给firstHello 。
第二个问题也是如此。
然后等待两者完成并打印结果。
此实现只是简化工作方式的一个示例。在实际代码中,您应该使用Task.WhenAll
等待所有正在运行的任务
答案 2 :(得分:3)
您还应该更喜欢返回Task
而不是void
(async/await - when to return a Task vs void?):
private static async Task SayHelloTwice()
{
var hellos = await Task.WhenAll(PrintTask(), PrintTask());
Console.WriteLine(hellos[0]);
Console.WriteLine(hellos[1]);
}