VB.NET运行总和在Parallel.for Synclock内的嵌套循环中丢失信息 [英] VB.NET running sum in nested loop inside Parallel.for Synclock loses information
问题描述
以下是我能够开发的最佳表示形式,用于计算嵌套在VB.NET(Visual Studio 2010,.NET Framework 4)的Parallel.for循环内的循环内的运行总和.请注意,当在屏幕上以和"显示结果时,两个和之间存在细微差异,因此在并行化变体中信息丢失.那么,信息如何丢失以及正在发生什么呢?在这种情况下,谁能提供一些有关方法的显微外科手术"以保持连续不断的增长? (请注意Parallel.for的新用户:我通常不使用从零开始的方法,因此在Parallel.for语句中,I1最多循环到101,因为代码使用101-1作为上限.这是因为MS开发了基于零计数器的并行代码):
Below is the best representation I have been able to develop for calculating a running sum inside a loop that's nested inside a Parallel.for loop in VB.NET (Visual Studio 2010, .NET Framework 4). Note that when showing the results in `sum' to the screen, there is a slight difference between the two sums, and hence loss of information in the parallelized variant. So how is the information being lost, and what's happening? Can anyone offer some "microsurgery" on methodology for keeping a running sum in this context? (Note to new users of Parallel.for: I typically don't use zero-based methods, so in the Parallel.for statement the I1 loops up to 101, since the code uses 101-1 as the upper bound. This is because MS developed the parallel code assuming zero-based counters):
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)
推荐答案
您正在使用double,而double根本不准确. 在非并行循环中,所有错误均直接存储在总和中.在并行循环中,您有一个附加的tmp,稍后将其添加到sum中.在非并行循环中使用相同的tmp(在内循环运行后加和),最终结果将是相等的.
You are working with doubles and double are simply not accurate. In the non parallel loop, all errors are stored directly in sum. In the parallel loop you have an additional tmp that is later added to sum. Use the same tmp in your non parallel loop (adding to sum after the inner loop has run) and eventually the results wil be equal then.
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)
Conclusion: If you work with double, then (a + b) + c is NOT (always) equal to 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
这篇关于VB.NET运行总和在Parallel.for Synclock内的嵌套循环中丢失信息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!