1.概念
WhenAll:接收一个Task数组作为参数,返回一个新的Task,该Task会在所有传入的Task都完成后完成。
WhenAny:接受一个Task数组作为参数,返回一个新的Task,该Task会在任意一个传入的Task完成后完成。
基本使用:
static async Task Main(string[] args)
{
int failed = 0;
var tasks = new List<Task>();
String[] urls =
{ "www.adatum.com", "www.cohovineyard.com",
"www.cohowinery.com", "www.northwindtraders.com",
"www.contoso.com" };
foreach (var value in urls)
{
var url = value;
tasks.Add(Task.Run(() =>
{
var png = new Ping();
try
{
var reply = png.Send(url);//对数组中的 URL 执行 ping 操作
if (!(reply.Status == IPStatus.Success))
{
Interlocked.Increment(ref failed);
throw new TimeoutException("Unable to reach " + url + ".");
}
}
catch (PingException)
{
Interlocked.Increment(ref failed);
throw;
}
}));
}
Task t = Task.WhenAll(tasks);
await t;
if (t.Status == TaskStatus.RanToCompletion)//以确定是否有任何任务出错。
Console.WriteLine("All ping attempts succeeded.");
else if (t.Status == TaskStatus.Faulted)
Console.WriteLine("{0} ping attempts failed", failed);
}
//结果:All ping attempts succeeded.
2.复杂应用
异步制作早餐场景:参考文档
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace AsyncBreakfast
{
class Program
{
static async Task Main(string[] args)
{
Coffee cup = PourCoffee();
Console.WriteLine("coffee is ready");
var eggsTask = FryEggsAsync(2);
var baconTask = FryBaconAsync(3);
var toastTask = MakeToastWithButterAndJamAsync(2);
var breakfastTasks = new List<Task> { eggsTask, baconTask, toastTask };
while (breakfastTasks.Count > 0)
{
Task finishedTask = await Task.WhenAny(breakfastTasks);
Console.WriteLine("等待WhenAny返回的第一个已完成的Task");
if (finishedTask == eggsTask)
{
Console.WriteLine("eggs are ready");
}
else if (finishedTask == baconTask)
{
Console.WriteLine("bacon is ready");
}
else if (finishedTask == toastTask)
{
Console.WriteLine("toast is ready");
}
//您应该再次等待该任务,即使您知道它已经完成运行。这就是如何检索它的结果,或者确保引发错误的异常被抛出。
await finishedTask;
breakfastTasks.Remove(finishedTask);
}
Juice oj = PourOJ();
Console.WriteLine("oj is ready");
Console.WriteLine("Breakfast is ready!");
}
static async Task<Toast> MakeToastWithButterAndJamAsync(int number)
{
var toast = await ToastBreadAsync(number);
ApplyButter(toast);
ApplyJam(toast);
return toast;
}
private static Juice PourOJ()
{
Console.WriteLine("Pouring orange juice");
return new Juice();
}
private static void ApplyJam(Toast toast) =>
Console.WriteLine("Putting jam on the toast");
private static void ApplyButter(Toast toast) =>
Console.WriteLine("Putting butter on the toast");
private static async Task<Toast> ToastBreadAsync(int slices)
{
for (int slice = 0; slice < slices; slice++)
{
Console.WriteLine("Putting a slice of bread in the toaster");
}
Console.WriteLine("Start toasting...");
await Task.Delay(3000);
Console.WriteLine("Remove toast from toaster");
return new Toast();
}
private static async Task<Bacon> FryBaconAsync(int slices)
{
Console.WriteLine($"putting {slices} slices of bacon in the pan");
Console.WriteLine("cooking first side of bacon...");
await Task.Delay(3000);
for (int slice = 0; slice < slices; slice++)
{
Console.WriteLine("flipping a slice of bacon");
}
Console.WriteLine("cooking the second side of bacon...");
await Task.Delay(3000);
Console.WriteLine("Put bacon on plate");
return new Bacon();
}
private static async Task<Egg> FryEggsAsync(int howMany)
{
Console.WriteLine("Warming the egg pan...");
await Task.Delay(3000);
Console.WriteLine($"cracking {howMany} eggs");
Console.WriteLine("cooking the eggs ...");
await Task.Delay(3000);
Console.WriteLine("Put eggs on plate");
return new Egg();
}
private static Coffee PourCoffee()
{
Console.WriteLine("Pouring coffee");
return new Coffee();
}
}
// These classes are intentionally empty for the purpose of this example. They are simply marker classes for the purpose of demonstration, contain no properties, and serve no other purpose.
internal class Bacon { }
internal class Coffee { }
internal class Egg { }
internal class Juice { }
internal class Toast { }
}