Dea*_*one 2 c# parallel-processing datatable parallel.foreach
我正在转换现有应用程序以利用多个处理器。我有一些嵌套循环,并且我已将最内层循环转换为 Parallel.Foreach 循环。在原始应用程序中,在最内层循环内,代码将调用DataTable.NewRow()实例化适当布局的新 DataRow、填充列并将填充的 DataRow 添加到带有 的 DataTable 中DataTable.Add()。但由于 DataTable 仅对于读取操作是线程安全的,因此我已转换处理以将填充的 DataRow 对象添加到对象中ConcurrentBag<DataRow>。然后,一旦 Parallel.Foreach 循环完成,我将迭代 ConcurrentBag 并将 DataRow 对象添加到 DataTable 中。它看起来像这样......
DataTable MyDataTable = new DataTable()
// Add columns to the data table
For(int OuterLoop = 1; OuterLoop < MaxValue; OuterLoop++)
{
//Do Stuff...
ConcurrentBag<DataRow> CB = new ConcurrentBag<DataRow>();
Parallel.Foreach(MyCollectionToEnumerate, x =>
{
//Do Stuff
DataRow dr = MyDataTable.NewRow();
// Populate dr...
CB.Add(dr);
{);
ForEach(DataRow d in CB)
MyDataTable.Add(d);
}
Run Code Online (Sandbox Code Playgroud)
因此,当运行时,我看到“索引超出了数组的范围”。调用时出现异常MyDataTable.NewRow()。但是 NewRow() 不是线程安全的 Read 操作吗?当然,它实例化了一个新的 DataRow 对象,但这不是读取。但它不需要修改 DataTable 对象,不是吗?
这可能会有所帮助...当我查看异常时,调用堆栈上的前两项是...
at System.Data.DataTable.NewRow(Int32 record)
at System.Data.DataTable.NewRow()
at ...
Run Code Online (Sandbox Code Playgroud)
我发现这NewRow()调用的一定是私有NewRow(int32)方法。所以也许这就是问题所在。但我不知道如何解决它。如果必须的话,我可以创建而不是在 Parallel.Foreach 循环中实例化 DataRow 对象,只需实例化一个看起来很像我的 DataTable 的自定义对象,一旦循环退出,实例化实际的 DataRows 并将它们添加到数据表。但这不太优雅,并且实例化了“不必要的”对象。我的目标是提高性能,所以这似乎适得其反。
感谢您的任何帮助。
不,NewRow不是“读”操作,也不是线程安全的。
NewRow您可以将值放入数组或列表中,而不是使用和填充行object。然后,当您收集了所有数据后,您可以将其全部添加到DataTable.
var newRow = table.NewRow();
newRow.ItemArray = values; // array of values
table.Rows.Add(newRow);
Run Code Online (Sandbox Code Playgroud)
这样,您就可以并行创建数据,而不会在将数据添加到DataTable.
查看源代码DataTable:
它包含多个字段:
private readonly DataRowBuilder rowBuilder;
internal readonly RecordManager recordManager;
Run Code Online (Sandbox Code Playgroud)
NewRow()调用NewRow(-1),并NewRow(int)修改这些字段的状态:
internal DataRow NewRow(int record) {
if (-1 == record) {
record = NewRecord(-1);
}
rowBuilder._record = record; // here
DataRow row = NewRowFromBuilder( rowBuilder );
recordManager[record] = row; // here
if (dataSet != null)
DataSet.OnDataRowCreated( row );
return row;
}
Run Code Online (Sandbox Code Playgroud)
......还有更多我没有遵循的。但显而易见的是,它NewRow()不仅仅返回一个新行,它还修改了DataTable整个实例的状态。
文档从未说过它是线程安全的,但我猜想,因为您仍然需要将行添加到表中,所以NewRow没有修改DataTable. 但我错了,它绝对不是线程安全的。
另一个标志位于文档中NewRow
创建 DataRow 后,可以通过 DataTable 对象的 Rows 属性将其添加到 DataRowCollection。当您使用 NewRow 创建新行时,必须在调用 Clear 之前将行添加到数据表中或从数据表中删除行。
它没有说明如果您调用Clear()而不添加或删除使用 创建的行会发生什么NewRow()。例外吗?我会死吗?所以我尝试了。我还在这里,但调用Clear()将每行中的所有值替换为DBNull.Value,进一步强调了这些行在被添加到DataTable. 他们是国家的一部分。
| 归档时间: |
|
| 查看次数: |
1597 次 |
| 最近记录: |