You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让对象列表的计算在Task.WhenAll阶段异步并行执行?

解决CPU密集型任务的多线程并行执行问题

你的问题根源在于**Calculate方法是同步逻辑伪装成异步签名**,它没有真正的异步操作,直接在调用线程同步执行完所有计算后返回Task.CompletedTask,所以在遍历调用model.Calculate()时,所有计算已经在Main线程跑完了,Task.WhenAll自然没有实际等待的任务。

下面给出几种可行的实现方案:

方案1:用Task.Run包装同步计算(推荐)

先把Calculate改成明确的同步方法(因为是CPU密集型逻辑),然后在创建任务时用Task.Run将计算逻辑分配到线程池线程执行:

using System;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Diagnostics;
                    
public class Program
{
    public static async Task Main()
    {
        List<Model> models = new List<Model>();
        for (int i = 100; i<10000; i++) {
            models.Add(new Model(i));
        }
        List<Task> list = new();
        var sw = new Stopwatch();
        sw.Start();
        foreach(var model in models)
        {
            // 用Task.Run将计算委托给线程池线程
            list.Add(Task.Run(() => model.Calculate()));
        }
        Console.WriteLine($"创建任务耗时:{sw.ElapsedMilliseconds}ms");
        sw.Restart();
        await Task.WhenAll(list);
        Console.WriteLine($"并行计算总耗时:{sw.ElapsedMilliseconds}ms");
    }
}

public class Model
{
    public double Result {get; set;}
    public int input {get; set;}
    public Model(int Input)  {
        input = Input;
        Result = 0;
    }
    // 同步CPU密集型计算方法
    public void Calculate() 
    {
        for (int i = 0; i < input; i++) {
            Result += i;
        }
    }
}

方案2:修改Calculate方法为真正的异步包装

如果需要保持Calculate的异步方法签名,可以在方法内部用Task.Run包裹计算逻辑:

public class Model
{
    // ... 其他成员不变
    public Task Calculate() 
    {
        // 将计算逻辑放到线程池执行,返回未完成的任务
        return Task.Run(() => {
            for (int i = 0; i < input; i++) {
                Result += i;
            }
        });
    }
}

方案3:用Parallel.ForEach简化并行逻辑(.NET Core/.NET 5+推荐)

如果不需要返回Task集合,直接用Parallel.ForEach可以更简洁地实现CPU密集型任务的并行执行:

public static void Main()
{
    List<Model> models = new List<Model>();
    for (int i = 100; i<10000; i++) {
        models.Add(new Model(i));
    }
    var sw = new Stopwatch();
    sw.Start();
    // 直接并行遍历执行计算
    Parallel.ForEach(models, model => model.Calculate());
    Console.WriteLine($"并行计算总耗时:{sw.ElapsedMilliseconds}ms");
}

关键注意点

  • 不要用return Task.CompletedTask来伪装异步方法,这会导致同步执行,完全失去并行意义。
  • CPU密集型任务适合用线程池线程执行(Task.Run/Parallel类),它们会自动利用多核CPU资源。
  • Task.WhenAll的作用是等待多个异步任务完成,前提是这些任务处于未完成状态,否则不会有任何等待效果。

内容的提问来源于stack exchange,提问作者rst

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 04:18:24