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

串行填充DataTable正常,并行填充时抛出异常求助

解决Parallel.ForEach填充DataTable的线程安全问题

这个问题我之前也碰到过,核心原因是DataTable及其关联的DataRowCollection都不是线程安全的——当多个线程同时调用dataTable.Rows.Add()这类修改共享表状态的操作时,会触发线程竞争,导致异常或数据错乱。下面给你两种靠谱的解决方案:

方案1:用线程安全集合缓存数据行,批量导入(推荐)

这种方式把并行操作和DataTable的修改解耦,并行只负责生成数据行,最后单线程批量添加,既保证安全又能保留并行的性能优势:

// 线程安全的集合,用来暂存每个线程生成的DataRow
var rowsCache = new ConcurrentBag<DataRow>();

Parallel.ForEach(items, item => {
    // 注意:NewRow()是线程安全的,它只是基于表结构创建空行,不会修改共享的DataTable状态
    DataRow newRow = dataTable.NewRow();
    newRow["column1"] = item.Value1;
    newRow["column2"] = item.Value2;
    rowsCache.Add(newRow);
});

// 并行处理完成后,单线程批量添加所有行到DataTable
foreach (var row in rowsCache)
{
    dataTable.Rows.Add(row);
}

// 最后执行排序
dataTable.DefaultView.Sort = "column1 asc";

方案2:加锁保护对DataTable的修改

如果必须在并行过程中直接添加行,可以用锁来确保同一时间只有一个线程操作DataTable的Rows集合,但这种方式会大幅降低并行效率(线程大部分时间在等锁),仅适合特殊场景:

// 创建专用的锁对象(不要用dataTable本身当锁,避免和其他操作冲突)
var tableLock = new object();

Parallel.ForEach(items, item => {
    DataRow newRow = dataTable.NewRow();
    newRow["column1"] = item.Value1;
    newRow["column2"] = item.Value2;

    // 加锁,保证只有一个线程能执行Rows.Add操作
    lock(tableLock)
    {
        dataTable.Rows.Add(newRow);
    }
});

dataTable.DefaultView.Sort = "column1 asc";

额外注意事项

  • 不要在并行操作中修改DataTable的结构(比如新增/删除列),这类操作的线程安全风险更高,且开销极大。
  • 如果你的items集合本身不是线程安全类型(比如普通List),要确保并行遍历期间没有其他线程修改它,否则也要同步保护。

内容的提问来源于stack exchange,提问作者Pavel S.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 07:47:02