以下parallel.for循环使用长度为300000位的比特阵列数据。并且数据固定不变。因此,无论执行“check”函数多少次,生成的结果“Count_of_Found_Pattern1”必须相同
但是,问题是“Count_of_Found_Pattern1”&的值。每次执行“check”功能时,“Count_of_Found_Pattern2”都会产生不同的值。我做错了什么?
当我使用少量位(大约16位而不是300位)检查它时,它会产生良好的结果。但是,当比特长度更长时,它会产生一团糟。
例如:
第一次执行 - > Count_of_Found_Pattern1 = 150526,Count_of_Found_Pattern2 = 97855
第二次执行 - > Count_of_Found_Pattern1 = 45855,Count_of_Found_Pattern2 = 187562
问候!
Private Function check()
Dim Count_of_Found_Pattern1 As Int64 = 0
Dim Count_of_Found_Pattern2 As Int64 = 0
Dim stopwatch As New Stopwatch
stopwatch.Start()
Dim Current_Position1 As Int64 = 0
Dim Current_Position2 As Int64 = 1
Parallel.For(0, lastbitarrayover2, Sub(countbits, loopstate)
If BitArray(Current_Position1) = False And BitArray(Current_Position2) = True Then
Count_of_Found_Pattern1 = Count_of_Found_Pattern1 + 1
End If
If BitArray(Current_Position1) = True And BitArray(Current_Position2) = False Then
Count_of_Found_Pattern1 = Count_of_Found_Pattern1 + 1
End If
If BitArray(Current_Position1) = True And BitArray(Current_Position2) = True Then
Count_of_Found_Pattern2 = Count_of_Found_Pattern2 + 1
End If
If BitArray(Current_Position1) = False And BitArray(Current_Position2) = False Then
Count_of_Found_Pattern2 = Count_of_Found_Pattern2 + 1
End If
Current_Position1 = Current_Position1 + 2
Current -Position2 = Current_Position2 + 2
Numer_of_Completed_Iterations = Numer_of_Completed_Iterations + 1
End Sub)
Numer_of_Completed_Iterations = 0 'reset counter to 0
stopwatch.Stop()
TextBox1.Text = stopwatch.Elapsed.ToString
End Function
答案 0 :(得分:0)
您是否尝试过System.Threading.Interlocked.Increment以使此线程安全?例如:
If BitArray(Current_Position1) = False And BitArray(Current_Position2) = True Then
Interlocked.Increment(Count_of_Found_Pattern1)
End If
答案 1 :(得分:0)
当你递增Count_of_Found_Pattern1(或Pattern2)时,首先读取该值,然后递增,然后分配。但是正在执行的线程可以在这三个步骤中发生变化。
Thread 1: Read Count_of_Found_Pattern1
Thread 2: Read Count_of_Found_Pattern1
Thread 2: Increment
Thread 2: Write to Count_of_Found_Pattern1
...
Thread 1: Increment its old value
Thread 1: Write to Count_of_Found_Pattern1
现在Count_of_Found_Pattern1错了。如果线程2控制执行超过一次迭代,那可能是非常错误的。
考虑在PLINQ中尽可能多地做,避免任何全局状态的突变,直到所有线程都加入备份。以下代码假定您对比较BitArray中的相邻条目感兴趣:
Dim counts = Enumerable.
Range(0, lastbitarrayover2 / 2).Select(Function(i) i * 2).
AsParallel().
Aggregate(
Function()
' We're using an object of anonymous type to hold
' the results of the calculation so far.
' Each thread calls this function, so each thread
' gets its own object for holding intermediate results
Return New With {.Pattern1 = 0, .Pattern2 = 0, .Iterations = 0}
End Function,
Function(accumulator, i)
' accumulator is this thread's intermediate-result-holder.
' i is one of the even numbers from our big set of even numbers.
' Each thread will call this function many times, building up its own accumulator object
' the four conditionals from your code reduce to this If block
If (BitArray(i) = BitArray(i + 1)) Then
accumulator.Pattern2 += 1
Else
accumulator.Pattern1 += 1
End If
accumulator.Iterations += 1
Return accumulator
End Function,
Function(acc1, acc2)
' Once each thread has built up its own accumulator object,
' this function makes a new accumulator object that
' combines the results from two threads.
' This is called repeatedly until all the threads' results
' have been combined.
Return New With {
.Pattern1 = acc1.Pattern1 + acc2.Pattern1,
.Pattern2 = acc1.Pattern2 + acc2.Pattern2,
.Iterations = acc1.Iterations + acc2.Iterations}
End Function,
Function(acc)
' The last function here is supposed to take the combined results
' and turn them into what you ultimately want to use.
' Since the combined results are already in the form we want,
' we'll just use the "identity" function here: it returns its
' argument unchanged
Return acc
End Function)
Count_of_Found_Pattern1 = counts.Pattern1
Count_of_Found_Pattern2 = counts.Pattern2
Number_of_Completed_Iterations = counts.Iterations
这可能看起来很多,但它确实不是太糟糕。主要的是我们给每个线程一组自己的变量来处理;这样我们就不必担心我在答案顶部列出的问题了。然后,我们结合每个线程最后完成的工作。