C# .NET 4.0为DataTable中的一列在所有行中添加相同的值

C# .NET 4.0为DataTable中的一列在所有行中添加相同的值,c#,datatable,.net-4.0,C#,Datatable,.net 4.0,我有以下数据表 DataTable dt = new dataTable(); 我用另一种方法填充了这个数据表。在执行以下语句之前,它将有50000行和40列 行和列的数量可能会有所不同。因此,我没有为dataTable定义特定的列集 我希望在末尾添加两列(guid和addeddate),并希望在所有50K行中为这两列添加相同的值 我已经为此编写了简单的foreach循环。有什么办法可以让我同时做吗 我尝试使用Parallel.Foreach,但没有成功 //by this time my d

我有以下数据表

DataTable dt = new dataTable();
我用另一种方法填充了这个数据表。在执行以下语句之前,它将有50000行和40列

行和列的数量可能会有所不同。因此,我没有为dataTable定义特定的列集

我希望在末尾添加两列(guid和addeddate),并希望在所有50K行中为这两列添加相同的值

我已经为此编写了简单的foreach循环。有什么办法可以让我同时做吗

我尝试使用Parallel.Foreach,但没有成功

//by this time my dt will have 50000 rows and 40 columns

dt.Columns.Add(new DataColumn("guid", typeof(string)));
dt.Columns.Add(new DataColumn("addeddate", typeof(DateTime)));
string sessionIDValue = Convert.ToString(Guid.NewGuid());
DateTime todayDt = DateTime.Today;                   


foreach (DataRow row in dt.Rows)
{
    row["guid"] = sessionIDValue;
    row["addeddate"] = todayDt;     
}

您需要使用显式索引访问行,而行索引将是实现这一点的完美方法

您应该能够创建一个数组,该数组的行数等于您拥有的行数(例如50000),每行的索引作为该数组的值(例如0..1..2..3..,等等),然后在该索引数组上使用并行循环,从而将显式行索引传递给dt.rows对象

守则的要点是:

// Pseudo code

// Create array equal to size of the # of rows (int ArrayOfIndexes[])
// Fill that array with values representing row indexes starting at 0

Parallel.ForEach(ArrayOfIndexes, (index) => 
{
    lock(dt)
    {
        dt.Rows[index]["guid"] = sessionIDValue;
        dt.Rows[index]["addeddate"] = todayDt;
    }
}

编辑:我确实发现,由于DataTable不是线程安全的,您必须在分配周围包含锁,这显然会影响性能,但应该比不使用Parallel.ForEach的简单循环更快。

您需要使用显式索引访问行,行索引将是实现这一点的完美方式

您应该能够创建一个数组,该数组的行数等于您拥有的行数(例如50000),每行的索引作为该数组的值(例如0..1..2..3..,等等),然后在该索引数组上使用并行循环,从而将显式行索引传递给dt.rows对象

守则的要点是:

// Pseudo code

// Create array equal to size of the # of rows (int ArrayOfIndexes[])
// Fill that array with values representing row indexes starting at 0

Parallel.ForEach(ArrayOfIndexes, (index) => 
{
    lock(dt)
    {
        dt.Rows[index]["guid"] = sessionIDValue;
        dt.Rows[index]["addeddate"] = todayDt;
    }
}

编辑:我确实发现,由于DataTable不是线程安全的,因此必须在分配周围包含锁,这显然会影响性能,但是仍然比没有Parallel.ForEach的简单循环要快。

升级@Shane Oborn的答案,不需要额外的ArrayOfIndexes变量,并使用单独的锁对象

我将使用:

var lockObj = new object();
Parallel.Foreach(dt.AsEnumerable(), row =>
{
    lock(lockObj)
    {
        row["guid"] = sessionIDValue;
        row["addeddate"] = todayDt;     
    }
});
您必须使用以下语句添加:

using System.Data.DataSetExtensions;
using System.Linq;
using System.Xml;

升级@Shane Oborn的答案,无需额外的ArrayOfIndexes变量,并使用单独的锁对象

我将使用:

var lockObj = new object();
Parallel.Foreach(dt.AsEnumerable(), row =>
{
    lock(lockObj)
    {
        row["guid"] = sessionIDValue;
        row["addeddate"] = todayDt;     
    }
});
您必须使用以下语句添加:

using System.Data.DataSetExtensions;
using System.Linq;
using System.Xml;

是否已尝试为要添加的数据列指定
DefaultValue
?我不敢预测它的性能有多好(如果它工作的话)。@Filburt是的,但是由于DataTable的结构不是固定的,我们无法提供它。您是否已经尝试为正在添加的DataColumns指定了
DefaultValue
?我不敢预测它的性能有多好(如果它工作的话)。@Filburt是的,但是由于DataTable的结构不是固定的,我们不能提供它,我认为在这里使用lock是没有意义的。即使您想这样做,最好的做法是拥有一个单独的lockObject+1对于Parallel.foreach,“锁”是为了防止在行值分配过程中出现间歇性错误,因为DataTable不是线程安全的。同意你的观点,分开锁定对象是个好主意。。。我基本上只是给出了解决方案的“本质”,而不是确切的解决方案我认为在这里使用锁是没有意义的。即使您想这样做,最好的做法是拥有一个单独的lockObject+1对于Parallel.foreach,“锁”是为了防止在行值分配过程中出现间歇性错误,因为DataTable不是线程安全的。同意你的观点,分开锁定对象是个好主意。。。我基本上只是给出了解决方案的“本质”,而不是确切的解决方案这不是真的,安东。正如我前面提到的,如果您使用这里的内容,然后在一个大小为5000的数组上尝试此操作,您会发现由于DataTable不是线程安全的,所以会出现“索引”错误。我已经测试过,您是对的,似乎不可能在没有锁的情况下并行编辑DataTable。在这种情况下,锁消除了并行性的所有好处……正确,如果上面的代码最终都被使用了,那么就没有好处了。但是,如果锁之外还有其他事情发生,显然在这种情况下会产生一些好处,但只与锁之外所做的工作量有关。是的,比如从第1列检查一些ip并在第2列中设置状态,这不是真的Anton。正如我前面提到的,如果您使用这里的内容,然后在一个大小为5000的数组上尝试此操作,您会发现由于DataTable不是线程安全的,所以会出现“索引”错误。我已经测试过,您是对的,似乎不可能在没有锁的情况下并行编辑DataTable。在这种情况下,锁消除了并行性的所有好处……正确,如果上面的代码最终都被使用了,那么就没有好处了。但是,如果在锁之外还有其他事情发生,显然在这种情况下会产生一些好处,但只与锁之外所做的工作量有关。是的,比如从第1列检查一些ip并在第2列中设置状态