串行填充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.
相关产品推荐
相关产品推荐

