我有3个任务:
private async Task<Cat> FeedCat() {}
private async Task<House> SellHouse() {}
private async Task<Tesla> BuyCar() {}
它们都需要在我的代码继续之前运行,我也需要每个结果。这些结果之间没有任何共同之处
我如何调用和等待3个任务完成,然后得到结果?
我有3个任务:
private async Task<Cat> FeedCat() {}
private async Task<House> SellHouse() {}
private async Task<Tesla> BuyCar() {}
它们都需要在我的代码继续之前运行,我也需要每个结果。这些结果之间没有任何共同之处
我如何调用和等待3个任务完成,然后得到结果?
当前回答
只需要分别等待这三个任务,在启动它们之后:
var catTask = FeedCat();
var houseTask = SellHouse();
var carTask = BuyCar();
var cat = await catTask;
var house = await houseTask;
var car = await carTask;
注意:如果任何一个任务抛出异常,这段代码可能会在后面的任务完成之前返回异常,但它们都将运行。在几乎所有的情况下,当你已经知道结果是理想的时候就不要等待。在边缘情况下,可能不是这样。
其他回答
var dn = await Task.WhenAll<dynamic>(FeedCat(),SellHouse(),BuyCar());
如果你想访问Cat,你可以这样做:
var ct = (Cat)dn[0];
这是非常简单的做法和非常有用的使用,没有必要去追求一个复杂的解决方案。
只需要分别等待这三个任务,在启动它们之后:
var catTask = FeedCat();
var houseTask = SellHouse();
var carTask = BuyCar();
var cat = await catTask;
var house = await houseTask;
var car = await carTask;
注意:如果任何一个任务抛出异常,这段代码可能会在后面的任务完成之前返回异常,但它们都将运行。在几乎所有的情况下,当你已经知道结果是理想的时候就不要等待。在边缘情况下,可能不是这样。
await语句不是使代码按顺序运行吗?考虑以下代码
class Program
{
static Stopwatch _stopwatch = new();
static async Task Main(string[] args)
{
Console.WriteLine($"fire hot");
_stopwatch.Start();
var carTask = BuyCar();
var catTask = FeedCat();
var houseTask = SellHouse();
await carTask;
await catTask;
await houseTask;
Console.WriteLine($"{_stopwatch.ElapsedMilliseconds} done!");
Console.WriteLine($"using await");
_stopwatch.Restart();
await BuyCar();
await FeedCat();
await SellHouse();
Console.WriteLine($"{_stopwatch.ElapsedMilliseconds} done!");
}
static async Task BuyCar()
{
Console.WriteLine($"{_stopwatch.ElapsedMilliseconds} buy car started");
await Task.Delay(2000);
Console.WriteLine($"{_stopwatch.ElapsedMilliseconds} buy car done");
}
static async Task FeedCat()
{
Console.WriteLine($"{_stopwatch.ElapsedMilliseconds} feed cat started");
await Task.Delay(1000);
Console.WriteLine($"{_stopwatch.ElapsedMilliseconds} feed cat done");
}
static async Task SellHouse()
{
Console.WriteLine($"{_stopwatch.ElapsedMilliseconds} sell house started");
await Task.Delay(10);
Console.WriteLine($"{_stopwatch.ElapsedMilliseconds} sell house done");
}
}
fire hot
0 buy car started
3 feed cat started
4 sell house started
18 sell house done
1004 feed cat done
2013 buy car done
2014 done!
using await
0 buy car started
2012 buy car done
2012 feed cat started
3018 feed cat done
3018 sell house started
3033 sell house done
3034 done!
The three tasks in your example differ greatly in importance. In case one of them fails, you probably want to know what happened with the others. For example in case the communication with the automatic cat feeder failed, you don't want to miss whether selling your house succeeded or failed. So it makes sense to return back not just a Cat, a House and a Tesla, but the tasks themselves. The calling code will then be able to query separately each of the three tasks, and react appropriately to their successful or failed completions:
public async Task<(Task<Cat>, Task<House>, Task<Tesla>)> FeedCatSellHouseBuyCar()
{
Task<Cat> task1 = FeedCat();
Task<House> task2 = SellHouse();
Task<Tesla> task3 = BuyCar();
// All three tasks are launched at this point.
try { await Task.WhenAll(task1, task2, task3).ConfigureAwait(false); } catch { }
// All three tasks are completed at this point.
return (task1, task2, task3);
}
使用的例子:
var (catTask, houseTask, teslaTask) = await FeedCatSellHouseBuyCar();
// All three tasks are completed at this point.
if (catTask.IsCompletedSuccessfully)
Console.WriteLine($"{catTask.Result.Name} is eating her healthy meal.");
else
Console.WriteLine("Your cat is starving!");
if (houseTask.IsCompletedSuccessfully)
Console.WriteLine($"Your house at {houseTask.Result.Address} was sold. You are now rich and homeless!");
else
Console.WriteLine("You are still the poor owner of your house.");
if (teslaTask.IsCompletedSuccessfully)
Console.WriteLine($"You are now the owner a battery-powered {teslaTask.Result.Name}.");
else
Console.WriteLine("You are still driving a Hyundai.");
带有空catch的try块是必需的,因为. net 7仍然没有提供适当的方法来等待任务,而不会在取消或失败时抛出。
当你使用WhenAll后,你可以用await单独拉出结果:
var catTask = FeedCat();
var houseTask = SellHouse();
var carTask = BuyCar();
await Task.WhenAll(catTask, houseTask, carTask);
var cat = await catTask;
var house = await houseTask;
var car = await carTask;
[注意异步方法总是返回“热”(已经启动的)任务。]
你也可以使用Task。结果(因为此时您知道它们都已成功完成)。但是,我推荐使用await,因为它显然是正确的,而Result在其他场景中可能会导致问题。