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

使用Parallel.Foreach批量创建对象仍耗时过长,求优化方案

批量创建Data对象的性能优化建议

嘿,4000条记录创建对象耗时超8秒确实有点反常,咱们来一步步拆解优化点,帮你把时间压下来:

  • 抛弃ConcurrentBag,改用PLINQ或预分配容量的List
    ConcurrentBag虽然是线程安全集合,但它的锁开销在并行创建对象场景下其实没必要——PLINQ的AsParallel().Select().ToList()会自动高效处理并行结果的收集,不需要手动维护线程安全集合。另外如果串行处理更高效(小数据集有时候并行调度开销反而更大),直接用预分配容量的List<data>(比如new List<data>(allRows.Count))也能避免List动态扩容的开销。

    示例(PLINQ版本):

    var lstdata = allRows.AsParallel()
                         .Select(row => new data 
                         { 
                             Id = row["NB"], 
                             ColumnId = row["COLUMN_ID"], 
                             Value = row["VALUE"] 
                         })
                         .ToList();
    
  • 优化行数据的访问方式
    如果你用的是DataRow这类对象,字符串索引器(row["NB"])每次都会做列名查找,开销很大。建议提前获取列的索引,用索引访问来替代:

    // 假设allRows里的元素是DataRow,提前获取列索引
    var sampleRow = (DataRow)allRows[0];
    int nbColIndex = sampleRow.Table.Columns["NB"].Ordinal;
    int columnIdColIndex = sampleRow.Table.Columns["COLUMN_ID"].Ordinal;
    int valueColIndex = sampleRow.Table.Columns["VALUE"].Ordinal;
    
    // 之后用索引访问
    var lstdata = allRows.AsParallel()
                         .Select(row => 
                         {
                             var dataRow = (DataRow)row;
                             return new data 
                             { 
                                 Id = dataRow[nbColIndex], 
                                 ColumnId = dataRow[columnIdColIndex], 
                                 Value = dataRow[valueColIndex] 
                             };
                         })
                         .ToList();
    
  • 减少装箱拆箱开销
    如果row中的字段是值类型(比如int、decimal),直接用row[...]会返回object,赋值给data属性时会发生拆箱。可以用强类型访问方法(比如DataRow的Field<T>)来避免:

    // 假设Id是int类型,Value是string类型
    return new data 
    { 
        Id = dataRow.Field<int>(nbColIndex), 
        ColumnId = dataRow.Field<int>(columnIdColIndex), 
        Value = dataRow.Field<string>(valueColIndex) 
    };
    
  • 检查Data类的额外开销
    看看你的data类的属性setter里有没有隐藏逻辑(比如数据验证、INotifyPropertyChanged通知),这些在批量创建时会累积大量开销。如果可以,尽量把这类逻辑延迟到批量创建完成后再执行。另外,若data是类,也可以考虑改用结构体(值类型),但要注意后续使用场景的复制开销,先测试再决定。

  • 测试并行vs串行的性能差异
    4000条数据其实不算特别大,Parallel.ForEach的线程调度开销可能超过并行带来的收益。可以试试串行版本,对比耗时:

    var lstdata = new List<data>(allRows.Count);
    foreach (var row in allRows)
    {
        var dataRow = (DataRow)row;
        lstdata.Add(new data 
        { 
            Id = dataRow.Field<int>(nbColIndex), 
            ColumnId = dataRow.Field<int>(columnIdColIndex), 
            Value = dataRow.Field<string>(valueColIndex) 
        });
    }
    

建议先从替换ConcurrentBag和优化行访问这两点入手,这两个是最容易见效的优化项。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 04:04:24