【问题标题】:Waiting for multiple Backgroundworkers to complete等待多个 Backgroundworkers 完成
【发布时间】:2018-02-10 09:38:45
【问题描述】:

我必须处理多个大型二维数组(例如 1024 x 128),并且在我的代码的一部分中我需要转置一些(最多 12 个)。 该过程需要相当长的时间,我正在尝试尽可能加快速度。知道 VB.NET 支持多线程,我在这里和那里阅读了不同的来源,并且可以在主子例程中提出以下代码:

RunXTransposingThreads(Arr1, Arr2, Arr3, ...)

使用BackgroundWorkers 作为我的解决方案的一部分:

Private Sub RunXTransposingThreads(ParamArray ArraysToTranspose() As Array)
    Dim x = CInt(ArraysToTranspose.GetLength(0)) - 1
    Dim i As Integer
    For i = 0 To x
        Dim worker As New System.ComponentModel.BackgroundWorker
        AddHandler worker.DoWork, AddressOf RunOneThread
        AddHandler worker.RunWorkerCompleted, AddressOf HandleThreadCompletion
        worker.RunWorkerAsync(ArraysToTranspose(i))
    Next
End Sub

Private Sub RunOneThread(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs)
    Dim Transposed(,) As Single = Array.CreateInstance(GetType(Single), 0, 0) ' I need this to be like that in order to use other functions later
    Transposed = Transpose2dArray(CType(e.Argument, Single(,)))
    e.Result = Transposed
End Sub

Private Sub HandleThreadCompletion(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs)
    Debug.Print("Process complete")
End Sub

Function Transpose2dArray(Of Array)(ByVal inArray As Array(,)) As Array(,)

    Dim x = CInt(inArray.GetLength(1))
    Dim y = CInt(inArray.GetLength(0))
    Dim outArray(x - 1, y - 1) As Array

    For i = 0 To x - 1
        For j = 0 To y - 1
            outArray(i, j) = inArray(j, i)
        Next
    Next

    Transpose2dArray = outArray

End Function

线程似乎可以工作,因为在执行RunXTransposingThreads 之后的某个时间,我在屏幕上看到了一些“进程完成”。问题是:如果我还没有转置数组,如何阻止 main 中的代码执行?

【问题讨论】:

  • BGW 已过时,完全被Task.Runasync/awaitIProgress< T> 取代。使用 Task.Run 开始大量任务并使用 Task.WhenAll(arrayOfTasks) 等待它们完成是微不足道的。另一方面,如果您想并行处理大量通过Parallel 方法已经可用的数据,例如Parallel.ForEachParallel.For
  • 我阅读了一些 Async/Await 的文档并列出了任务,但我似乎无法让任务返回一些结果。
  • 您可能需要再次阅读文档。无论如何,您需要并行处理,而不是任务。那是 Parallel 或 PLINQ,例如 Parallel.ForEach(arrayOfArrays,Transpose2dArray)arrayOfArrays.AsParallel().Select(arr=>Transpose2dArray(arr)).ToArray()
  • @AndrewMorton 是的,那是一个例外,之前是控制的。正如我已经写的那样,循环被执行,因为后来我得到了几个“进程完成”
  • @PanagiotisKanavos 请您写一个带有一点代码的答案,这样我实际上可以理解您使用AsParallel 的意思吗? C#代码也可以

标签: vb.net multithreading multidimensional-array backgroundworker


【解决方案1】:

正如其他人所说,BackgroundWorker 已过时。幸运的是,还有许多其他现代方法可以做到这一点。

因此,我不会向您展示使您的代码与 BackgroundWorker 一起使用的东西。相反,我将向您展示如何通过使用任务(其中一种现代方式)来做同样的事情。希望对您有所帮助。

Function RunXTransposingTasks(ParamArray ArraysToTranspose() As Array) As Array
    Dim taskList = New List(Of Task(Of Single(,))) ' our tasks returns Arrays

    For Each arr In ArraysToTranspose
        Dim r = arr
        taskList.Add(Task.Run(Function() Transpose2dArray(r)))
    Next

    Task.WhenAll(taskList) ' wait for all tasks to complete. 
    Return taskList.Select(Function(t) t.Result).ToArray()
End Function

Function Transpose2dArray(inArray As Array) As Single(,)
    Dim x = inArray.GetLength(1) - 1
    Dim y = inArray.GetLength(0) - 1
    Dim outArray(x, y) As Single

    For i = 0 To x
        For j = 0 To y
            outArray(i, j) = inArray(j, i)
        Next
    Next

    Return outArray
End Function

' Usage
' Dim result = RunXTransposingTasks(Arr1, Arr2, Arr3, ...)

【讨论】:

  • 避免Task.StartNew,改用Task.Run
  • 为什么不让函数异步并实际等待WhenAll 调用,而不是调用阻塞.Result 调用?
  • @Nkosi 你又是对的。你为什么不添加一个更好的答案? :) 我觉得我会从这个答案中学到很多东西。
【解决方案2】:

您可以尝试使用build-in function 复制数据

Array.Copy(inArray, outArray, CInt(inArray.GetLength(1)) * CInt(inArray.GetLength(0)))

还有一些关于如何使用 Parallel.ForEach 的 great example

【讨论】:

  • 好的,关于Array.Copy,谢谢,但我认为这个例子没有帮助。我在 Main 中看到了大量关于如何使用 Parallel.ForEach 的示例,但我似乎找不到关于修改作为输入给出的数据的合适示例...
猜你喜欢
  • 1970-01-01
  • 2015-02-25
  • 2016-10-16
  • 1970-01-01
  • 2012-12-01
  • 2018-02-24
  • 1970-01-01
相关资源
最近更新 更多