在 Parallel.For 中调用子例程(并将变量 ByRef 传递给它)线程安全吗?

Is calling a subroutine inside Parallel.For (and passing a variable ByRef to it) thread safe?

我在嵌套的 Parallel.For 循环 (vb.net) 中调用子程序 MyPartsMatrix。 MyPartsMatrix 需要一个名为 "unfilled" 的变量,该变量通过 ByRef 传递,因为该值在 MyPartsMatrix 子例程中被修改。我需要在子程序 MyPartsMatrix 执行后获取并存储这个值。

当我 运行 此代码的并行版本与使用普通嵌套 For...Next 循环的非并行版本相比时,"unfilled" 变量产生不同的值。我想不通为什么会这样。

从 Parallel.For 循环内部调用另一个子例程是否线程安全?

这个变量"unfilled"线程安全吗?

    Dim ConcurrentListofResults As ConcurrentQueue(Of FindBestResults)
    ConcurrentListofResults = New ConcurrentQueue(Of FindBestResults)

    Dim x = 5, y = 5

    Parallel.For(0, x, Sub(oD)
                           Parallel.For(0, y, Sub(oT)

                                                  Dim unfilled As Integer = 0
                                                  MyPartsMatrix (oD, oT, unfilled)

                                                  'Create a FBS item to add to the concurrent list collection
                                                  Dim FBSResultsItem = New FindBestResults
                                                  FBSResultsItem.oD = oD
                                                  FBSResultsItem.oT = oT
                                                  FBSResultsItem.unfilled = unfilled

                                                  'Add this item to the Concurent collection
                                                  ConcurrentListofResults.Enqueue(FBSResultsItem)

                                              End Sub)
                       End Sub)
    'Get best result.
    Dim bestResult As FindBestResults
    For Each item As FindBestResults In ConcurrentListofResults
        If item.unfilled < bestResult.unfilled Then
            bestResult.oD = item.oD
            bestResult.oT = item.oT
            bestResult.unfilled = item.unfilled
        End If
    Next

    Public Sub MyPartsMatrix (ByVal oD As Integer, ByVal oT As Integer, ByRef unfilled As Integer)

      '....do stuff with the unfilled variable....
      'unfilled is a counter that is incremented while we run through the PartsMatrix
       unfilled = unfilled + 1  
    End Sub

如果这不是线程安全的,是否有另一种方法来编写它,以便 "unfilled" 变量是线程安全的或使调用另一个子例程线程安全?

没有 MakeSchedule 的定义(你在另一个地方称之为 MyMakePartsMatrix )就不可能说它是否是线程安全的。

为了线程安全,sub 不需要修改除 unfilled 之外的任何内容。这将确保使用相同的输入多次调用它总是会产生相同的输出。我还建议转换为函数,因为我发现这更容易理解发生了什么。

另一个注意事项:

如果不嵌套并行循环,您的性能会更好。在启动第二个循环之前,您目前正在等待内部循环完成。如果您使用更大的 x + y 值,那么类似于代码的东西会更好。

    Dim scenarios = From x2 In Enumerable.Range(0, x)
        From y2 In Enumerable.Range(0, y)
        Select New With {x2, y2}

    Parallel.ForEach(scenarios, Sub(s)

                                End Sub)