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

如何在C#中并行执行同步计算任务以充分利用多CPU资源?

在C#中如何并行执行同步计算任务以充分利用多CPU资源?

我手里有大量金融数据数组,需要为程序中的每个证券(任意时刻有10至100个代码)执行6个及以上基于该数组的纯计算同步函数。同步函数定义如下:

public double DoWork(double[] bigArray, double[] history)
{
    double risk = 0;
    <calculate risk synchronously>
    return risk;
}

我的初步思路是用Task.Run来并行执行,但觉得写法不够自然,因为Task.Run看起来像是要传入返回Task的函数:

var tasks = List<Task>();
tasks.Add(Task.Run(() => DoWork(bigArray, days30)));
tasks.Add(Task.Run(() => DoWork(bigArray, days60)));
tasks.Add(Task.Run(() => DoWork(bigArray, days90)));
tasks.Add(Task.Run(() => DoWork(bigArray, days120)));
await Task.WhenAll(tasks);

可行的解决方案

1. 修正Task.Run的用法(其实完全可用)

Task.Run本身支持接收同步委托,会自动把同步方法包装成Task<T>返回,你之前的写法只是没正确接收返回值。调整后更合理的写法:

var tasks = new List<Task<double>>();
tasks.Add(Task.Run(() => DoWork(bigArray, days30)));
tasks.Add(Task.Run(() => DoWork(bigArray, days60)));
tasks.Add(Task.Run(() => DoWork(bigArray, days90)));
tasks.Add(Task.Run(() => DoWork(bigArray, days120)));

// 等待所有任务完成并获取结果
double[] allResults = await Task.WhenAll(tasks);

这样既能并行执行,又能拿到每个任务的计算结果,写法其实很直接。

2. 用Parallel类(更适配CPU密集型任务)

因为你的任务是纯CPU计算,Parallel类是专门为这类场景设计的,它会自动根据CPU核心数优化并行调度,比手动管理Task更高效。

  • 执行多个独立的计算任务:
double result30 = 0, result60 = 0, result90 = 0, result120 = 0;

// 并行执行所有委托
Parallel.Invoke(
    () => result30 = DoWork(bigArray, days30),
    () => result60 = DoWork(bigArray, days60),
    () => result90 = DoWork(bigArray, days90),
    () => result120 = DoWork(bigArray, days120)
);

// 之后直接使用result30、result60等变量
  • 批量处理多个证券:
    如果需要给每个证券都执行多组计算,用Parallel.ForEach更合适,配合线程安全容器存储结果:
// 假设你的证券集合,每个证券包含不同天数的history数据
var securities = GetAllSecurities();
// 线程安全字典,key为证券代码,value为多组计算结果
var calculationResults = new ConcurrentDictionary<string, double[]>();

Parallel.ForEach(securities, security => {
    var day30Risk = DoWork(bigArray, security.Days30History);
    var day60Risk = DoWork(bigArray, security.Days60History);
    var day90Risk = DoWork(bigArray, security.Days90History);
    // ...其他天数的计算

    calculationResults.TryAdd(security.Code, new[] { day30Risk, day60Risk, day90Risk });
});

3. 用Task.Factory.StartNew(自定义并行配置)

如果需要更精细的控制(比如指定任务优先级、是否长时间运行),可以用Task.Factory.StartNew:

var task30 = Task.Factory.StartNew(() => DoWork(bigArray, days30), TaskCreationOptions.None);
var task60 = Task.Factory.StartNew(() => DoWork(bigArray, days60), TaskCreationOptions.None);

await Task.WhenAll(task30, task60);
double risk30 = task30.Result;
double risk60 = task60.Result;

注意事项

  • 线程安全:你的bigArray是只读的纯输入数据,所以不用担心并行访问的线程安全问题;如果涉及可写的共享数据,必须用线程安全容器(如ConcurrentDictionary)或手动加锁。
  • 并行度控制:如果任务数量远多于CPU核心数,Parallel类会自动调整;也可以手动指定最大并行度,避免占用过多资源:
var options = new ParallelOptions { 
    MaxDegreeOfParallelism = Environment.ProcessorCount // 用当前CPU核心数
};
Parallel.ForEach(securities, options, security => {
    // 执行计算
});
  • 避免无效并行:如果单个任务的计算量极小,并行调度的开销可能超过收益,这种情况建议串行执行;但金融计算通常计算量较大,并行是划算的。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 22:43:22