异步进阶:C#的Task.WhenAll——如何开启多个异步任务

发布于:2025-07-10 ⋅ 阅读:(25) ⋅ 点赞:(0)

Task.WhenAll 是 .NET 中用于并行等待多个异步任务的核心方法。它可以让多个异步操作同时执行,然后一次性等待所有任务完成,而不是逐个等待。

async void Main()
{
    // 准备数据:[1,2,3,4,5,6,7,8,9,10]
    var inputs = Enumerable.Range(1,10).ToArray();
    var outputs = new List<int>();
    
    // ❌ 错误方式:串行执行(一个接一个)
    //foreach (var element in inputs)
    //{
    //    var result = await HeavyJobAsync(element);  // 等待当前任务完成
    //    outputs.Add(result);                       // 再开始下一个
    //}
    // 总耗时:10 × 200ms = 2000ms
    
    // ✅ 正确方式:使用 Task.WhenAll 并行执行
    var tasks = new List<Task<int>>();
    
    // 第一步:启动所有任务(不等待结果)
    foreach (var element in inputs)
    {
        // 关键:这里创建并启动任务,但不 await,任务立即开始在后台执行
        tasks.Add(HeavyJobAsync(element));
    }
    
    // 第二步:使用 Task.WhenAll 等待所有任务完成
    await Task.WhenAll(tasks);  // 🎯 重点!
    
    // 第三步:收集所有任务的结果
    outputs = tasks.Select(t => t.Result).ToList();
    
    outputs.Dump();  // 输出:[1,4,9,16,25,36,49,64,81,100]
}

// 模拟耗时异步操作
async Task<int> HeavyJobAsync(int input)
{
    await Task.Delay(200);  // 模拟200ms的工作
    return input * input;   // 返回平方值
}

分析

方式1的问题:
foreach (var element in inputs)
{
    var result = await HeavyJobAsync(element);  //这里会"阻塞"
    // 程序会在这里停下来等待,直到HeavyJobAsync完成
    // 然后才会执行下一次循环
}
方式2的优势:
// 第一步:快速启动所有任务
foreach (var element in inputs)
{
    tasks.Add(HeavyJobAsync(element));  // 只是启动,不等待
    // HeavyJobAsync立即返回Task对象,实际工作在后台进行
}

// 第二步:统一等待所有任务完成
await Task.WhenAll(tasks);  // 一次性等待所有任务

Task.WhenAll 的不同用法

1. 有返回值的任务

// 启动多个任务
var task1 = GetDataAsync(1);
var task2 = GetDataAsync(2);
var task3 = GetDataAsync(3);

// 等待所有任务并获取结果
int[] results = await Task.WhenAll(task1, task2, task3);
// results = [result1, result2, result3] 按顺序排列

2. 无返回值的任务

// 启动多个任务
var task1 = SaveDataAsync(data1);
var task2 = SaveDataAsync(data2);
var task3 = SaveDataAsync(data3);

// 等待所有任务完成
await Task.WhenAll(task1, task2, task3);

3. 动态任务集合

// 动态创建任务列表
var tasks = urls.Select(url => DownloadAsync(url)).ToList();

// 等待所有下载完成
string[] contents = await Task.WhenAll(tasks);

使用场景

同时调用多个Web服务、同时读写多个文件、数据库操作:并行执行多个查询。

Task.WhenAny vs Task.WhenAll 核心区别

特性 Task.WhenAll Task.WhenAny
等待策略 等待所有任务完成 等待任何一个任务完成
完成条件 最慢的任务完成时 最快的任务完成时
返回结果 所有任务的结果数组 第一个完成的任务对象
用途 并行处理,需要所有结果 竞争场景,只要第一个结果


网站公告

今日签到

点亮在社区的每一天
去签到