用Parallel.For汇总C#Datatable列?

用Parallel.For汇总C#Datatable列?,c#,multithreading,.net-4.0,parallel-processing,task-parallel-library,C#,Multithreading,.net 4.0,Parallel Processing,Task Parallel Library,我有这个数据表: DataTable dt=GetDatatTable() 其中一列是金额(十进制) 我想用TPL尽可能快地总结一下 object obj = new Object(); var total=0m; Parallel.For (1, dt.Rows.Count+1 ,i => {lock (obj) total += Decimal.Parse(dt.Rows[i-1]["Amount"]) }); 但是我真的不想在周围锁很多次 问题1

我有这个数据表:

DataTable dt=GetDatatTable()

其中一列是
金额
(十进制)

我想用
TPL
尽可能快地总结一下

  object obj  = new Object();
  var total=0m;
  Parallel.For (1, dt.Rows.Count+1  ,i => {lock (obj) total += Decimal.Parse(dt.Rows[i-1]["Amount"]) });
但是我真的不想在周围锁很多次

问题1

有没有其他方法可以减少大量锁

问题2

我不明白为什么我需要保护总蓄能器

  • 该保护是针对
    +=
    还是针对多线程更新
    总数

    我的意思是看下面的流程,一个
    Volatile
    字段可以很容易地解决它

    假设
    total=0

    数据表项为
    1,2,3

    1)第一个线程:总计=总计+1。(总计=1)

    2)第二个线程:total=total+
    \uuuuuuuuu stop\uuuuuu
    (上下文切换,线程3的值为3)
    \uuuuuuuu val=\uuuuu3\uuuuuuuuuuu
    (total=1+3=4)

    3)上下文切换回线程2总计=4+2=6

    看来一切都很好

我一定是遗漏了什么

p.s. 我知道我可以用:

ParallelEnumerable.Range (1, dt.Rows.Count+1).Sum (i => Decimal.Parse(dt.Rows[i-1]["Amount"]) )

但是我想学习如何使用
并行。对于

来说,由于需要使用锁定来确保正确的结果,我不认为
并行。因为
可以为您带来任何好处。你不能同时锁定某些东西;根据定义,锁定是串联完成的


因此,一个简单的
for
循环将同样具有性能,并且更易于使用。

是的,有其他方法可以减少锁:

  • 使用。这样,您只需要在
    localFinally
    委托中进行同步(但您不应该在那里忘记它)
  • 使用
    Interlocked.Add()
    。这在您的情况下不起作用,因为只有
    int
    long
    有重载,而不是
    decimal
  • 不要使用并行处理。对于这样一个非常简单的操作,并行处理的开销很可能超过速度的提高
  • 使用PLINQ:

    var total =
        ParallelEnumerable.Range(0, dt.Rows.Count)
                          .Select(i => Decimal.Parse(dt.Rows[i]["Amount"]))
                          .Sum();
    

  • 关于线程安全问题,您假设在“上下文切换”(我使用可怕的引号,因为在多核CPU上,发生此问题不需要任何上下文切换)之后,线程将再次读取当前值
    total
    。但事实上,它已经读取了旧值,该值现在保存在寄存器中。因此,步骤3中的结果将变为1+2=3。

    这里有一点关于
    volatile
    的注释。您可以查看(即,
    AsParallel().Sum(x=>…)
    当然,如果这符合您的需要;我很久没有接触过原始数据表了,所以我很难说最好的做法是什么…@Trustme-I'maDoctor请查看我的编辑。好吧,我个人认为除了在这种特殊情况下使用锁之外,没有其他简单的方法。也许其他人会有更好的主意:)顺便说一句,我认为你的代码中有一个错误。如果你想有一个基于1的
    i
    (虽然我在这里看不到任何原因),你需要
    并行。对于(1,count+1,…)
    @svick是的,你是对的。我写这篇文章只是为了回答这个问题,但我会修正的。谢谢。谢谢svick,不应该读取最新值吗?(对不起,我不明白你是如何得到1+3=3的。你能详细说明一下吗?)对不起,这是我的一个输入错误,现已修复。是的,它将读取最新值,但它将在切换之前读取。当时,最新值为1。与
    total=total+a
    相比,两者之间存在差异?在多线程环境中…不,这两者之间没有任何区别。在这两种情况下,都是1。将
    总计
    读取到寄存器;2.将
    a
    添加到寄存器中;3.将
    总计
    写回。如果其他线程在步骤1和步骤3之间更改
    total
    的值,则存在争用条件。