21、Task

Task.WhenAll 和 Task.WhenAny

知识点

Task.WhenAll 基础

  • 并行等待:等待所有任务完成,所有任务并行执行
  • 结果收集:自动收集所有任务的返回值到数组中
  • 异常聚合:收集所有任务的异常,第一个异常会被抛出
  • 性能优势:比逐个等待任务更高效

Task.WhenAny 基础

  • 竞争执行:等待任意一个任务完成即返回
  • 快速响应:获取最快完成的任务结果
  • 超时实现:常用于实现超时机制
  • 冗余处理:多个数据源中选择最快的响应

使用场景对比

  • WhenAll:需要所有结果才能继续的场景(如数据聚合)
  • WhenAny:任意一个结果就足够的场景(如多服务器请求)
  • 组合使用:复杂场景中两者可以组合使用
  • 错误处理:两者在异常处理上有不同的行为

代码样例

Task.WhenAll 基本使用

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Linq;

public class WhenAllBasicDemo
{
    public static void DemonstrateWhenAllBasic()
    {
        Console.WriteLine("=== Task.WhenAll 基本使用演示 ===");

        // 1. 无返回值任务的 WhenAll
        Console.WriteLine("1. 无返回值任务的 WhenAll:");
        DemonstrateWhenAllVoidTasks();

        // 2. 有返回值任务的 WhenAll
        Console.WriteLine("\n2. 有返回值任务的 WhenAll:");
        DemonstrateWhenAllWithResults();

        // 3. 混合类型任务的处理
        Console.WriteLine("\n3. 混合类型任务的处理:");
        DemonstrateMixedTaskTypes();

        Console.WriteLine("Task.WhenAll 基本使用演示完成\n");
    }

    private static void DemonstrateWhenAllVoidTasks()
    {
        var stopwatch = System.Diagnostics.Stopwatch.StartNew();

        // 创建多个无返回值任务
        Task[] tasks = new Task[]
        {
            Task.Run(() =>
            {
                Console.WriteLine("  任务A开始");
                Thread.Sleep(1000);
                Console.WriteLine("  任务A完成");
            }),

            Task.Run(() =>
            {
                Console.WriteLine("  任务B开始");
                Thread.Sleep(1500);
                Console.WriteLine("  任务B完成");
            }),

            Task.Run(() =>
            {
                Console.WriteLine("  任务C开始");
                Thread.Sleep(800);
                Console.WriteLine("  任务C完成");
            })
        };

        // 等待所有任务完成
        Task.WhenAll(tasks).Wait();

        stopwatch.Stop();
        Console.WriteLine($"  所有任务完成,总耗时: {stopwatch.ElapsedMilliseconds}ms");
    }

    private static void DemonstrateWhenAllWithResults()
    {
        var stopwatch = System.Diagnostics.Stopwatch.StartNew();

        // 创建多个有返回值的任务
        Task<int>[] calculationTasks = new Task<int>[]
        {
            Task.Run(() =>
            {
                Console.WriteLine("  计算任务1: 求和 1-100");
                Thread.Sleep(500);
                return Enumerable.Range(1, 100).Sum();
            }),

            Task.Run(() =>
            {
                Console.WriteLine("  计算任务2: 求积 1-10");
                Thread.Sleep(800);
                return Enumerable.Range(1, 10).Aggregate(1, (acc, x) => acc * x);
            }),

            Task.Run(() =>
            {
                Console.WriteLine("  计算任务3: 求平方和 1-20");
                Thread.Sleep(600);
                return Enumerable.Range(1, 20).Select(x => x * x).Sum();
            })
        };

        // 等待所有任务并获取结果
        int[] results = Task.WhenAll(calculationTasks).Result;

        stopwatch.Stop();

        Console.WriteLine("  所有计算完成:");
        for (int i = 0; i < results.Length; i++)
        {
            Console.WriteLine($"    计算任务{i + 1}结果: {results[i]}");
        }
        Console.WriteLine($"  总耗时: {stopwatch.ElapsedMilliseconds}ms");
    }

    private static void DemonstrateMixedTaskTypes()
    {
        // 字符串任务
        Task<string>[] stringTasks = new Task<string>[]
        {
            Task.Run(() =>
            {
                Thread.Sleep(400);
                return "Hello";
            }),
            Task.Run(() =>
            {
                Thread.Sleep(600);
                return "World";
            }),
            Task.Run(() =>
            {
                Thread.Sleep(300);
                return "!";
            })
        };

        // 数字任务
        Task<int>[] numberTasks = new Task<int>[]
        {
            Task.Run(() =>
            {
                Thread.Sleep(500);
                return 42;
            }),
            Task.Run(() =>
            {
                Thread.Sleep(700);
                return 100;
            })
        };

        // 分别等待不同类型的任务
        Task<string[]> stringResults = Task.WhenAll(stringTasks);
        Task<int[]> numberResults = Task.WhenAll(numberTasks);

        // 等待所有分组完成
        Task.WhenAll(stringResults, numberResults).Wait();

        Console.WriteLine("  字符串结果: " + string.Join(" ", stringResults.Result));
        Console.WriteLine("  数字结果: " + string.Join(", ", numberResults.Result));
    }
}

Task.WhenAny 基本使用

public class WhenAnyBasicDemo
{
    public static void DemonstrateWhenAnyBasic()
    {
        Console.WriteLine("=== Task.WhenAny 基本使用演示 ===");

        // 1. 基本的 WhenAny
        Console.WriteLine("1. 基本的 WhenAny:");
        DemonstrateBasicWhenAny();

        // 2. 获取最快的结果
        Console.WriteLine("\n2. 获取最快的结果:");
        DemonstrateFastestResult();

        // 3. 超时实现
        Console.WriteLine("\n3. 超时实现:");
        DemonstrateTimeoutImplementation();

        Console.WriteLine("Task.WhenAny 基本使用演示完成\n");
    }

    private static void DemonstrateBasicWhenAny()
    {
        var stopwatch = System.Diagnostics.Stopwatch.StartNew();

        Task[] tasks = new Task[]
        {
            Task.Run(() =>
            {
                Console.WriteLine("  慢任务开始 (3秒)");
                Thread.Sleep(3000);
                Console.WriteLine("  慢任务完成");
            }),

            Task.Run(() =>
            {
                Console.WriteLine("  快任务开始 (1秒)");
                Thread.Sleep(1000);
                Console.WriteLine("  快任务完成");
            }),

            Task.Run(() =>
            {
                Console.WriteLine("  中等任务开始 (2秒)");
                Thread.Sleep(2000);
                Console.WriteLine("  中等任务完成");
            })
        };

        // 等待任意一个任务完成
        Task completedTask = Task.WhenAny(tasks).Result;
        stopwatch.Stop();

        Console.WriteLine($"  第一个完成的任务索引: {Array.IndexOf(tasks, completedTask)}");
        Console.WriteLine($"  等待时间: {stopwatch.ElapsedMilliseconds}ms");

        // 检查其他任务的状态
        for (int i = 0; i < tasks.Length; i++)
        {
            Console.WriteLine($"  任务{i}状态: {tasks[i].Status}");
        }
    }

    private static void DemonstrateFastestResult()
    {
        // 模拟从多个数据源获取数据
        Task<string>[] dataSources = new Task<string>[]
        {
            FetchFromDataSource("数据库", 1500),
            FetchFromDataSource("缓存", 300),
            FetchFromDataSource("API", 1000),
            FetchFromDataSource("文件", 800)
        };

        var stopwatch = System.Diagnostics.Stopwatch.StartNew();

        // 获取最快的响应
        Task<string> fastestTask = Task.WhenAny(dataSources).Result;
        string fastestResult = fastestTask.Result;

        stopwatch.Stop();

        Console.WriteLine($"  最快的响应: {fastestResult}");
        Console.WriteLine($"  响应时间: {stopwatch.ElapsedMilliseconds}ms");

        // 显示其他数据源的状态
        Console.WriteLine("  其他数据源状态:");
        for (int i = 0; i < dataSources.Length; i++)
        {
            var task = dataSources[i];
            string status = task.IsCompleted ?
                (task.IsCompletedSuccessfully ? "已完成" : "失败") : "进行中";
            Console.WriteLine($"    数据源{i + 1}: {status}");
        }
    }

    private static Task<string> FetchFromDataSource(string sourceName, int delay)
    {
        return Task.Run(() =>
        {
            Console.WriteLine($"    开始从{sourceName}获取数据...");
            Thread.Sleep(delay);
            string result = $"来自{sourceName}的数据";
            Console.WriteLine($"    {result} (耗时{delay}ms)");
            return result;
        });
    }

    private static void DemonstrateTimeoutImplementation()
    {
        var timeouts = new[] { 500, 1500, 2500 };

        foreach (int timeoutMs in timeouts)
        {
            Console.WriteLine($"\n  测试 {timeoutMs}ms 超时:");

            // 创建一个长时间运行的任务
            Task<string> longTask = Task.Run(() =>
            {
                Console.WriteLine("    长任务开始 (预计2秒)");
                Thread.Sleep(2000);
                return "长任务完成";
            });

            // 创建超时任务
            Task timeoutTask = Task.Delay(timeoutMs);

            // 等待第一个完成的任务
            Task completedTask = Task.WhenAny(longTask, timeoutTask).Result;

            if (completedTask == timeoutTask)
            {
                Console.WriteLine($"    操作超时 ({timeoutMs}ms)");
            }
            else
            {
                Console.WriteLine($"    操作完成: {longTask.Result}");
            }
        }
    }
}

高级使用模式

public class AdvancedWhenAllAnyDemo
{
    public static void DemonstrateAdvancedPatterns()
    {
        Console.WriteLine("=== 高级使用模式演示 ===");

        // 1. 分批处理
        Console.WriteLine("1. 分批处理:");
        DemonstrateBatchProcessing().Wait();

        // 2. 容错处理
        Console.WriteLine("\n2. 容错处理:");
        DemonstrateFaultTolerantProcessing().Wait();

        // 3. 进度追踪
        Console.WriteLine("\n3. 进度追踪:");
        DemonstrateProgressTracking().Wait();

        Console.WriteLine("高级使用模式演示完成\n");
    }

    private static async Task DemonstrateBatchProcessing()
    {
        // 模拟大量数据项
        var dataItems = Enumerable.Range(1, 20).ToArray();
        const int batchSize = 5;

        Console.WriteLine($"  处理 {dataItems.Length} 个数据项,批次大小: {batchSize}");

        var allResults = new List<string>();

        // 分批处理
        for (int i = 0; i < dataItems.Length; i += batchSize)
        {
            var batch = dataItems.Skip(i).Take(batchSize).ToArray();
            Console.WriteLine($"  处理批次 {i / batchSize + 1}: 项目 {i + 1}-{Math.Min(i + batchSize, dataItems.Length)}");

            // 并行处理当前批次
            var batchTasks = batch.Select(item => ProcessDataItemAsync(item)).ToArray();
            string[] batchResults = await Task.WhenAll(batchTasks);

            allResults.AddRange(batchResults);
            Console.WriteLine($"    批次完成,获得 {batchResults.Length} 个结果");
        }

        Console.WriteLine($"  所有批次完成,总共获得 {allResults.Count} 个结果");
    }

    private static async Task<string> ProcessDataItemAsync(int item)
    {
        // 模拟数据处理
        await Task.Delay(200);
        return $"已处理项目{item}";
    }

    private static async Task DemonstrateFaultTolerantProcessing()
    {
        // 创建一些可能失败的任务
        var tasks = new[]
        {
            CreateReliableTask("任务A", 300, 0.1),  // 10% 失败率
            CreateReliableTask("任务B", 500, 0.3),  // 30% 失败率
            CreateReliableTask("任务C", 400, 0.0),  // 不会失败
            CreateReliableTask("任务D", 600, 0.5),  // 50% 失败率
            CreateReliableTask("任务E", 350, 0.2)   // 20% 失败率
        };

        Console.WriteLine("  启动容错任务处理...");

        var successfulResults = new List<string>();
        var failedTasks = new List<string>();

        try
        {
            // 等待所有任务完成(忽略异常)
            await Task.WhenAll(tasks.Select(async task =>
            {
                try
                {
                    string result = await task;
                    lock (successfulResults)
                    {
                        successfulResults.Add(result);
                    }
                }
                catch (Exception ex)
                {
                    lock (failedTasks)
                    {
                        failedTasks.Add($"失败: {ex.Message}");
                    }
                }
            }));
        }
        catch
        {
            // 忽略外层异常,我们已经在内部处理了
        }

        Console.WriteLine($"  处理完成:");
        Console.WriteLine($"    成功: {successfulResults.Count} 个");
        Console.WriteLine($"    失败: {failedTasks.Count} 个");

        foreach (string result in successfulResults)
        {
            Console.WriteLine($"    ✓ {result}");
        }

        foreach (string failure in failedTasks)
        {
            Console.WriteLine($"    ✗ {failure}");
        }
    }

    private static async Task<string> CreateReliableTask(string taskName, int delay, double failureRate)
    {
        await Task.Delay(delay);

        if (new Random().NextDouble() < failureRate)
        {
            throw new Exception($"{taskName} 随机失败");
        }

        return $"{taskName} 成功完成";
    }

    private static async Task DemonstrateProgressTracking()
    {
        var tasks = new[]
        {
            CreateProgressTask("文件下载", 2000),
            CreateProgressTask("数据处理", 1500),
            CreateProgressTask("结果上传", 1800),
            CreateProgressTask("邮件发送", 800),
            CreateProgressTask("日志记录", 600)
        };

        Console.WriteLine($"  开始追踪 {tasks.Length} 个任务的进度...");

        var completedTasks = new List<Task>();
        var remainingTasks = tasks.ToList();

        while (remainingTasks.Any())
        {
            // 等待下一个任务完成
            Task completedTask = await Task.WhenAny(remainingTasks);
            completedTasks.Add(completedTask);
            remainingTasks.Remove(completedTask);

            // 报告进度
            int completedCount = completedTasks.Count;
            int totalCount = tasks.Length;
            int progressPercent = (completedCount * 100) / totalCount;

            Console.WriteLine($"    进度: {completedCount}/{totalCount} ({progressPercent}%) " +
                            $"- 最新完成: {await completedTask}");
        }

        Console.WriteLine("  所有任务完成!");
    }

    private static async Task<string> CreateProgressTask(string taskName, int duration)
    {
        await Task.Delay(duration);
        return taskName;
    }
}

异常处理模式

public class ExceptionHandlingDemo
{
    public static void DemonstrateExceptionHandling()
    {
        Console.WriteLine("=== 异常处理模式演示 ===");

        // 1. WhenAll 的异常处理
        Console.WriteLine("1. WhenAll 的异常处理:");
        DemonstrateWhenAllExceptions().Wait();

        // 2. WhenAny 的异常处理
        Console.WriteLine("\n2. WhenAny 的异常处理:");
        DemonstrateWhenAnyExceptions().Wait();

        // 3. 混合异常处理
        Console.WriteLine("\n3. 混合异常处理:");
        DemonstrateMixedExceptionHandling().Wait();

        Console.WriteLine("异常处理模式演示完成\n");
    }

    private static async Task DemonstrateWhenAllExceptions()
    {
        var tasks = new[]
        {
            CreateTaskWithPossibleException("任务A", 500, false),
            CreateTaskWithPossibleException("任务B", 300, true),   // 会失败
            CreateTaskWithPossibleException("任务C", 700, false),
            CreateTaskWithPossibleException("任务D", 400, true)    // 会失败
        };

        try
        {
            string[] results = await Task.WhenAll(tasks);
            Console.WriteLine("  所有任务成功完成:");
            foreach (string result in results)
            {
                Console.WriteLine($"    {result}");
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"  WhenAll 捕获到异常: {ex.Message}");

            // 检查每个任务的详细状态
            Console.WriteLine("  详细任务状态:");
            for (int i = 0; i < tasks.Length; i++)
            {
                var task = tasks[i];
                if (task.IsCompletedSuccessfully)
                {
                    Console.WriteLine($"    任务{i + 1}: 成功 - {task.Result}");
                }
                else if (task.IsFaulted)
                {
                    Console.WriteLine($"    任务{i + 1}: 失败 - {task.Exception?.InnerException?.Message}");
                }
                else if (task.IsCanceled)
                {
                    Console.WriteLine($"    任务{i + 1}: 已取消");
                }
                else
                {
                    Console.WriteLine($"    任务{i + 1}: {task.Status}");
                }
            }
        }
    }

    private static async Task<string> CreateTaskWithPossibleException(string taskName, int delay, bool shouldFail)
    {
        await Task.Delay(delay);

        if (shouldFail)
        {
            throw new InvalidOperationException($"{taskName} 故意失败");
        }

        return $"{taskName} 成功";
    }

    private static async Task DemonstrateWhenAnyExceptions()
    {
        var tasks = new[]
        {
            CreateTaskWithPossibleException("快速失败任务", 200, true),
            CreateTaskWithPossibleException("慢速成功任务", 1000, false),
            CreateTaskWithPossibleException("中速失败任务", 600, true)
        };

        try
        {
            Task<string> completedTask = await Task.WhenAny(tasks);

            // 检查完成的任务是否成功
            if (completedTask.IsCompletedSuccessfully)
            {
                Console.WriteLine($"  第一个完成的任务成功: {completedTask.Result}");
            }
            else if (completedTask.IsFaulted)
            {
                Console.WriteLine($"  第一个完成的任务失败: {completedTask.Exception?.InnerException?.Message}");
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"  WhenAny 异常: {ex.Message}");
        }

        // 等待一段时间,让其他任务也完成
        await Task.Delay(1200);

        Console.WriteLine("  所有任务最终状态:");
        for (int i = 0; i < tasks.Length; i++)
        {
            var task = tasks[i];
            string status = task.IsCompletedSuccessfully ? "成功" :
                           task.IsFaulted ? "失败" :
                           task.IsCanceled ? "取消" : task.Status.ToString();
            Console.WriteLine($"    任务{i + 1}: {status}");
        }
    }

    private static async Task DemonstrateMixedExceptionHandling()
    {
        Console.WriteLine("  实现任务结果收集器...");

        var tasks = new[]
        {
            CreateTaskWithPossibleException("API调用1", 300, false),
            CreateTaskWithPossibleException("API调用2", 500, true),
            CreateTaskWithPossibleException("API调用3", 400, false),
            CreateTaskWithPossibleException("API调用4", 600, true),
            CreateTaskWithPossibleException("API调用5", 350, false)
        };

        var results = new List<string>();
        var errors = new List<string>();

        // 为每个任务包装异常处理
        var wrappedTasks = tasks.Select(async (task, index) =>
        {
            try
            {
                string result = await task;
                lock (results)
                {
                    results.Add($"API{index + 1}: {result}");
                }
            }
            catch (Exception ex)
            {
                lock (errors)
                {
                    errors.Add($"API{index + 1}: {ex.Message}");
                }
            }
        });

        // 等待所有包装任务完成
        await Task.WhenAll(wrappedTasks);

        Console.WriteLine($"  收集完成:");
        Console.WriteLine($"    成功结果: {results.Count} 个");
        foreach (string result in results)
        {
            Console.WriteLine($"      ✓ {result}");
        }

        Console.WriteLine($"    错误结果: {errors.Count} 个");
        foreach (string error in errors)
        {
            Console.WriteLine($"      ✗ {error}");
        }
    }
}

实际应用场景

public class PracticalApplicationsDemo
{
    public class WebScrapingManager
    {
        public async Task<string[]> ScrapeMultipleUrlsAsync(string[] urls, int maxConcurrent = 3)
        {
            Console.WriteLine($"开始抓取 {urls.Length} 个URL,最大并发: {maxConcurrent}");

            var results = new List<string>();

            // 分批处理,控制并发数
            for (int i = 0; i < urls.Length; i += maxConcurrent)
            {
                var batch = urls.Skip(i).Take(maxConcurrent).ToArray();
                Console.WriteLine($"  处理批次 {i / maxConcurrent + 1}: {batch.Length} 个URL");

                var batchTasks = batch.Select(url => ScrapeUrlAsync(url)).ToArray();

                try
                {
                    string[] batchResults = await Task.WhenAll(batchTasks);
                    results.AddRange(batchResults);
                    Console.WriteLine($"    批次完成,获得 {batchResults.Length} 个结果");
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"    批次失败: {ex.Message}");

                    // 逐个检查任务结果
                    foreach (var task in batchTasks)
                    {
                        if (task.IsCompletedSuccessfully)
                        {
                            results.Add(task.Result);
                        }
                    }
                }
            }

            return results.ToArray();
        }

        private async Task<string> ScrapeUrlAsync(string url)
        {
            await Task.Delay(500 + new Random().Next(1000)); // 模拟网络延迟

            // 模拟偶尔的失败
            if (new Random().Next(5) == 0)
            {
                throw new Exception($"无法访问 {url}");
            }

            return $"来自 {url} 的内容";
        }
    }

    public class LoadBalancer
    {
        public async Task<T> GetFastestResponseAsync<T>(Func<Task<T>>[] serviceCallFactories)
        {
            Console.WriteLine($"向 {serviceCallFactories.Length} 个服务发送请求...");

            // 创建所有服务调用任务
            var tasks = serviceCallFactories.Select((factory, index) =>
                CallServiceWithLogging(factory, index)).ToArray();

            // 等待第一个成功的响应
            while (tasks.Any(t => !t.IsCompleted))
            {
                Task<T> completedTask = await Task.WhenAny(tasks);

                if (completedTask.IsCompletedSuccessfully)
                {
                    Console.WriteLine("  获得第一个成功响应");
                    return completedTask.Result;
                }
                else
                {
                    Console.WriteLine("  一个服务调用失败,继续等待其他服务...");
                    // 从待等待任务中移除失败的任务
                    tasks = tasks.Where(t => t != completedTask && !t.IsCompleted).ToArray();
                }
            }

            throw new Exception("所有服务调用都失败了");
        }

        private async Task<T> CallServiceWithLogging<T>(Func<Task<T>> serviceCallFactory, int serviceIndex)
        {
            try
            {
                Console.WriteLine($"    服务{serviceIndex + 1} 开始调用");
                T result = await serviceCallFactory();
                Console.WriteLine($"    服务{serviceIndex + 1} 调用成功");
                return result;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"    服务{serviceIndex + 1} 调用失败: {ex.Message}");
                throw;
            }
        }
    }

    public static void DemonstratePracticalApplications()
    {
        Console.WriteLine("=== 实际应用场景演示 ===");

        // 1. Web 抓取管理器
        Console.WriteLine("1. Web 抓取管理器:");
        DemonstrateWebScraping().Wait();

        // 2. 负载均衡器
        Console.WriteLine("\n2. 负载均衡器:");
        DemonstrateLoadBalancer().Wait();

        // 3. 数据聚合服务
        Console.WriteLine("\n3. 数据聚合服务:");
        DemonstrateDataAggregation().Wait();

        Console.WriteLine("实际应用场景演示完成\n");
    }

    private static async Task DemonstrateWebScraping()
    {
        var scraper = new WebScrapingManager();
        var urls = new[]
        {
            "http://site1.com", "http://site2.com", "http://site3.com",
            "http://site4.com", "http://site5.com", "http://site6.com",
            "http://site7.com"
        };

        try
        {
            string[] results = await scraper.ScrapeMultipleUrlsAsync(urls, maxConcurrent: 3);
            Console.WriteLine($"抓取完成,获得 {results.Length} 个结果:");
            foreach (string result in results.Take(3)) // 只显示前3个
            {
                Console.WriteLine($"  {result}");
            }
            if (results.Length > 3)
            {
                Console.WriteLine($"  ... 还有 {results.Length - 3} 个结果");
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"抓取失败: {ex.Message}");
        }
    }

    private static async Task DemonstrateLoadBalancer()
    {
        var loadBalancer = new LoadBalancer();

        // 模拟多个服务
        Func<Task<string>>[] services = new Func<Task<string>>[]
        {
            () => SimulateServiceCall("服务A", 1200, 0.3), // 慢但相对可靠
            () => SimulateServiceCall("服务B", 800, 0.5),  // 中等速度,经常失败
            () => SimulateServiceCall("服务C", 400, 0.7),  // 快但不可靠
            () => SimulateServiceCall("服务D", 600, 0.2)   // 较快且可靠
        };

        try
        {
            string result = await loadBalancer.GetFastestResponseAsync(services);
            Console.WriteLine($"负载均衡结果: {result}");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"负载均衡失败: {ex.Message}");
        }
    }

    private static async Task<string> SimulateServiceCall(string serviceName, int delay, double failureRate)
    {
        await Task.Delay(delay);

        if (new Random().NextDouble() < failureRate)
        {
            throw new Exception($"{serviceName} 不可用");
        }

        return $"来自{serviceName}的响应";
    }

    private static async Task DemonstrateDataAggregation()
    {
        Console.WriteLine("聚合多个数据源的信息...");

        // 模拟从不同数据源获取数据
        var dataTasks = new[]
        {
            GetUserProfile("用户基本信息"),
            GetUserPreferences("用户偏好"),
            GetUserActivity("用户活动"),
            GetUserStats("用户统计")
        };

        try
        {
            string[] dataResults = await Task.WhenAll(dataTasks);

            Console.WriteLine("数据聚合完成:");
            foreach (string data in dataResults)
            {
                Console.WriteLine($"  ✓ {data}");
            }

            // 组合所有数据
            string aggregatedData = string.Join(" | ", dataResults);
            Console.WriteLine($"\n聚合结果: {aggregatedData}");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"数据聚合失败: {ex.Message}");

            // 尝试获取部分数据
            var partialResults = new List<string>();
            foreach (var task in dataTasks)
            {
                if (task.IsCompletedSuccessfully)
                {
                    partialResults.Add(task.Result);
                }
            }

            if (partialResults.Any())
            {
                Console.WriteLine($"获得部分数据: {string.Join(" | ", partialResults)}");
            }
        }
    }

    private static async Task<string> GetUserProfile(string dataType)
    {
        await Task.Delay(300);
        return dataType;
    }

    private static async Task<string> GetUserPreferences(string dataType)
    {
        await Task.Delay(500);
        return dataType;
    }

    private static async Task<string> GetUserActivity(string dataType)
    {
        await Task.Delay(400);
        return dataType;
    }

    private static async Task<string> GetUserStats(string dataType)
    {
        await Task.Delay(600);
        return dataType;
    }
}

综合演示

public class ComprehensiveWhenAllAnyDemo
{
    public static void RunAllDemos()
    {
        Console.WriteLine("Task.WhenAll 和 Task.WhenAny 综合演示");
        Console.WriteLine("=".PadRight(60, '='));

        // 1. Task.WhenAll 基本使用
        WhenAllBasicDemo.DemonstrateWhenAllBasic();

        // 2. Task.WhenAny 基本使用
        WhenAnyBasicDemo.DemonstrateWhenAnyBasic();

        // 3. 高级使用模式
        AdvancedWhenAllAnyDemo.DemonstrateAdvancedPatterns();

        // 4. 异常处理模式
        ExceptionHandlingDemo.DemonstrateExceptionHandling();

        // 5. 实际应用场景
        PracticalApplicationsDemo.DemonstratePracticalApplications();

        Console.WriteLine("所有 WhenAll/WhenAny 演示完成");
    }
}

总结

Task.WhenAll 的核心特点

  1. 并行执行:所有任务同时开始,并行执行
  2. 等待全部完成:必须等待所有任务都完成才返回
  3. 结果聚合:自动收集所有任务的返回值到数组中
  4. 异常行为:任何一个任务失败都会导致整体失败,但会等待所有任务完成

Task.WhenAny 的核心特点

  1. 竞争执行:等待第一个完成的任务
  2. 快速响应:一旦有任务完成就立即返回
  3. 结果选择:返回第一个完成的任务,需要手动获取结果
  4. 异常独立:只关心第一个完成的任务的状态

性能优势对比

  • WhenAll vs 逐个等待:WhenAll 允许任务并行执行,总时间等于最慢任务的时间
  • WhenAny vs 轮询检查:WhenAny 使用高效的事件机制,避免了轮询开销
  • 内存效率:两者都比手动管理任务状态更节省内存

异常处理策略

  1. WhenAll 异常:第一个异常会被抛出,但可以检查所有任务的详细状态
  2. WhenAny 异常:需要手动检查完成任务的状态
  3. 容错处理:通过包装任务来实现容错逻辑
  4. 部分成功:在某些场景下可以接受部分任务失败

最佳实践建议

  1. 选择合适的方法:根据业务需求选择 WhenAll 或 WhenAny
  2. 控制并发数:使用分批处理控制并发任务数量
  3. 异常处理:根据业务需要决定是否容忍部分失败
  4. 资源管理:及时处理完成的任务,避免资源泄漏

常见应用场景

  1. WhenAll 场景:数据聚合、批量处理、并行计算
  2. WhenAny 场景:超时实现、负载均衡、冗余处理
  3. 组合使用:复杂业务流程中两者可以组合使用
  4. 监控和诊断:进度追踪、性能监控、故障诊断

注意事项

  • 任务生命周期:WhenAny 完成后其他任务仍在运行
  • 取消传播:确保取消令牌正确传播到所有任务
  • 内存考虑:长时间运行的任务可能导致内存积累
  • 调试复杂性:并行任务的调试比顺序执行更复杂
posted @ 2025-08-27 01:24  jessqiu  阅读(30)  评论(0)    收藏  举报