0

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

    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()
    MsgBox(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()
    MsgBox(sum & "  " & clock.ElapsedMilliseconds)    
4

1 回答 1

0

您正在使用双打,而双打根本不准确。在非并行循环中,所有错误都直接存储在 sum 中。在并行循环中,您有一个额外的 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
于 2012-11-28T16:49:36.220 回答