VB.NET在Parallel.for Synclock内的嵌套循环中运行求和会丢失信息

VB.NET在Parallel.for Synclock内的嵌套循环中运行求和会丢失信息,vb.net,nested,floating-accuracy,parallel.foreach,Vb.net,Nested,Floating Accuracy,Parallel.foreach,下面是我为计算嵌套在VB.NET(Visual Studio 2010,.NET Framework 4)中Parallel.for循环中的循环中的运行和而开发的最佳表示。请注意,当在屏幕上显示“sum”中的结果时,两个和之间存在细微差异,因此在并行化变量中会丢失信息。那么信息是如何丢失的,发生了什么?在这种情况下,有人能提供一些“显微外科”方法来保持一个连续的总数吗?(请注意Parallel.for的新用户:我通常不使用基于零的方法,因此在Parallel.for语句中,I1循环到101,因为

下面是我为计算嵌套在VB.NET(Visual Studio 2010,.NET Framework 4)中Parallel.for循环中的循环中的运行和而开发的最佳表示。请注意,当在屏幕上显示“sum”中的结果时,两个和之间存在细微差异,因此在并行化变量中会丢失信息。那么信息是如何丢失的,发生了什么?在这种情况下,有人能提供一些“显微外科”方法来保持一个连续的总数吗?(请注意Parallel.for的新用户:我通常不使用基于零的方法,因此在Parallel.for语句中,I1循环到101,因为代码使用101-1作为上限。这是因为MS开发的并行代码假设使用基于零的计数器):


您正在使用双打,而双打根本不准确。 在非并行循环中,所有错误都直接存储在总和中。在并行循环中,您有一个额外的tmp,稍后添加到sum中。在非并行循环中使用相同的tmp(在内部循环运行后添加到sum),最终结果将相等

 Dim sum As Double = 0
    Dim lock As New Object
    Dim clock As New Stopwatch
    Dim i, j As Integer
    clock.Start()
    sum = 0
    For i = 1 To 100
        For j = 1 To 100
            sum += Math.Log(0.9999)
        Next j
    Next i
    clock.Stop()
    Console.WriteLine(sum & "  " & clock.ElapsedMilliseconds)
    sum = 0
    clock.Reset()

    clock.Start()
    sum = 0
    For i = 1 To 100
        Dim tmp As Double = 0
        For j = 1 To 100
            tmp += Math.Log(0.9999)
        Next
        sum += tmp
    Next i
    clock.Stop()
    Console.WriteLine(sum & "  " & clock.ElapsedMilliseconds)
    sum = 0
    clock.Reset()

    clock.Start()
    Parallel.For(1, 101, Sub(i1)
                             Dim temp As Double = 0
                             For j1 As Integer = 1 To 100
                                 temp += Math.Log(0.9999)
                             Next
                             SyncLock lock
                                 sum += temp
                             End SyncLock
                         End Sub)
    clock.Stop()
    Console.WriteLine(sum & "  " & clock.ElapsedMilliseconds)

End Sub
输出:

-1,00005000333357  0
-1,00005000333347  0
-1,00005000333347  26
结论:如果你使用double,那么(a+b)+c并不(总是)等于a+(b+c)

更新

更简单的例子是:

    Dim sum As Double
    For i = 1 To 100
        sum += 0.1
    Next
    Console.WriteLine(sum)

    sum = 0
    For i = 1 To 2
        Dim tmp As Double = 0
        For j = 1 To 50
            tmp += 0.1
        Next
        sum += tmp
    Next
    Console.WriteLine(sum)
现在输出是

9,99999999999998
10

谢谢你的建议,他们做得很好。但是,关于double不准确的说法听起来好像您知道一种具有更高数字精度的VisualStudio变量类型?你用什么比double更准确?@LEP:
Decimal
更准确。当然,它需要更多的内存,计算速度也要慢得多,因为CPU不直接支持
Decimal
。我有很多嵌套循环,其中包含大量代码段以及许多矩阵的处理。你能推荐一种合适的方法来捆绑并行程序中的大量工作吗?(我认为会有很多基于lambda的问题。)
9,99999999999998
10