Parallel.ForEachAsync 是 .NET 6 引入的一个强大 API,它确实会实现并行处理,但需要理解其具体的并行机制。

核心要点

Parallel.ForEachAsync并行执行异步操作,但它不是通过创建大量线程来实现,而是通过 任务并行 的方式,利用线程池高效地并发处理多个异步操作。

基本用法

csharp

using var httpClient = new HttpClient();

var urls = new[]
{
    "https://api.example.com/1",
    "https://api.example.com/2",
    "https://api.example.com/3"
};

// 并行处理多个异步操作
await Parallel.ForEachAsync(urls, async (url, cancellationToken) =>
{
    var response = await httpClient.GetStringAsync(url, cancellationToken);
    Console.WriteLine($"处理完成: {url}, 长度: {response.Length}");
});

控制并行度

可以通过 ParallelOptions 设置最大并行度:

csharp

var options = new ParallelOptions
{
    MaxDegreeOfParallelism = 3,  // 最多同时处理3个操作
    CancellationToken = cancellationToken
};

await Parallel.ForEachAsync(items, options, async (item, token) =>
{
    await ProcessItemAsync(item, token);
});

重要特性

  1. 并行执行:多个迭代会同时执行(受 MaxDegreeOfParallelism 限制)

  2. 异步友好:专门设计用于异步委托,不会阻塞线程

  3. 线程池利用:底层使用 Task 和线程池,不会为每个操作创建专用线程

  4. 顺序不保证:处理完成的顺序与输入顺序无关

与 Task.WhenAll 的区别

csharp

// Parallel.ForEachAsync - 控制并发度,适合大量操作
await Parallel.ForEachAsync(items, 
    new ParallelOptions { MaxDegreeOfParallelism = 10 },
    async (item, token) => await ProcessAsync(item));

// Task.WhenAll - 全部并发,无并发度控制
await Task.WhenAll(items.Select(item => ProcessAsync(item)));

注意事项

  • 委托必须是异步的(返回 ValueTaskTask

  • 默认并行度是环境处理器数,但实际并发数受线程池调度影响

  • 适用于 I/O 密集型操作(如 HTTP 请求、数据库查询)

  • CPU 密集型操作建议使用 Parallel.ForEach

总之,Parallel.ForEachAsync 确实实现了并行处理,并且是以一种高效、可扩展的方式管理大量异步操作的并发执行。