如何等待所有线程完成而又不阻塞VB.NET中的UI?

时间:2019-02-08 08:30:07

标签: .net vb.net multithreading

我要在运行时优化的 VB.NET Framework 4.0应用程序中有一个大型的初始化例程。由于当今大多数计算机能够一次执行多个线程,因此我想引入多线程来并行执行非依赖性,因此减少了用户初始化应用程序的总时间。

原始(单线程)实现如下所示:

Friend Module MainModule

    Friend Sub Main()
        LongRunningInitialization1()
        LongRunningInitialization2()
        LongRunningInitialization3()
        LongRunningInitialization4()
        LongRunningInitialization5()
        LongRunningInitialization6()
        LongRunningInitialization7()
    End Sub

    Private Sub LongRunningInitialization1()
    End Sub

    Private Sub LongRunningInitialization2()
    End Sub

    Private Sub LongRunningInitialization3()
    End Sub

    Private Sub LongRunningInitialization4()
    End Sub

    Private Sub LongRunningInitialization5()
    End Sub

    Private Sub LongRunningInitialization6()
    End Sub

    Private Sub LongRunningInitialization7()
    End Sub

End Module

我的第一种方法是使用System.Threading.Thread来并行化工作负载:

Friend Sub Main()
    Dim thread1 As New Threading.Thread(AddressOf LongRunningInitialization1)
    Dim thread2 As New Threading.Thread(AddressOf LongRunningInitialization2)
    Dim thread3 As New Threading.Thread(AddressOf LongRunningInitialization3)
    Dim thread4 As New Threading.Thread(AddressOf LongRunningInitialization4)
    Dim thread5 As New Threading.Thread(AddressOf LongRunningInitialization5)
    Dim thread6 As New Threading.Thread(AddressOf LongRunningInitialization6)
    Dim thread7 As New Threading.Thread(AddressOf LongRunningInitialization7)
    thread1.Join()
    thread2.Join()
    thread3.Join()
    thread4.Join()
    thread5.Join()
    thread6.Join()
    thread7.Join()
End Sub

尽管这项基本工作有效,Join()是一个阻塞调用,并且在thread1花费时间最长的场景中,只要thread1完成,其他线程都是“僵尸” 。另外,由于Join()被阻止,因此未实现的带有进度条的初始屏幕冻结。

我通过使用线程的while and the ThreadState`属性以一种怪异的方式进行非阻塞等待而提出了另一个“解决方案”:

Friend Sub Main()
    Dim thread1 As New Threading.Thread(AddressOf LongRunningInitialization1)
    Dim thread2 As New Threading.Thread(AddressOf LongRunningInitialization2)
    Dim thread3 As New Threading.Thread(AddressOf LongRunningInitialization3)
    Dim thread4 As New Threading.Thread(AddressOf LongRunningInitialization4)
    Dim thread5 As New Threading.Thread(AddressOf LongRunningInitialization5)
    Dim thread6 As New Threading.Thread(AddressOf LongRunningInitialization6)
    Dim thread7 As New Threading.Thread(AddressOf LongRunningInitialization7)
    While thread1.ThreadState = Threading.ThreadState.Running _
        OrElse thread2.ThreadState = Threading.ThreadState.Running _
        OrElse thread3.ThreadState = Threading.ThreadState.Running _
        OrElse thread4.ThreadState = Threading.ThreadState.Running _
        OrElse thread5.ThreadState = Threading.ThreadState.Running _
        OrElse thread6.ThreadState = Threading.ThreadState.Running _
        OrElse thread7.ThreadState = Threading.ThreadState.Running
        Application.DoEvents() ' process the Windows Forms message queue.
        Threading.Thread.Sleep(1) ' non-blocking wait.
    End While
    thread1.Join()
    thread2.Join()
    thread3.Join()
    thread4.Join()
    thread5.Join()
    thread6.Join()
    thread7.Join()
End Sub

尽管此最后一个实现在此示例中有效,但是当您面对现实世界中大约有20个长时间运行的初始化任务(大多数应并行运行)时,它不可用。 while条件的规模将是史诗般的。

是否有一种解决方案可以对所有创建的线程执行非阻塞等待? 以下伪代码之类的东西:

Friend Sub Main()
    Dim threadPool As New PseudoThreadPool()
    threadPool.Add(New Threading.Thread(AddressOf LongRunningInitialization1))
    threadPool.Add(New Threading.Thread(AddressOf LongRunningInitialization2))
    threadPool.Add(New Threading.Thread(AddressOf LongRunningInitialization3))
    threadPool.Add(New Threading.Thread(AddressOf LongRunningInitialization4))
    threadPool.Add(New Threading.Thread(AddressOf LongRunningInitialization5))
    threadPool.Add(New Threading.Thread(AddressOf LongRunningInitialization6))
    threadPool.Add(New Threading.Thread(AddressOf LongRunningInitialization7))
    threadPool.Start()
    While threadPool.AllDone = False
        Application.DoEvents() ' process the Windows Forms message queue.
        Threading.Thread.Sleep(1) ' non-blocking wait.
    End While
    threadPool.Join()
End Sub

1 个答案:

答案 0 :(得分:1)

由于@Jimi(List(Of Task)方法),我找到了解决方案。

Friend Sub Main()
    Dim tasks As New List(Of Task)
    tasks.Add(New Task(AddressOf LongRunningInitialization1))
    tasks.Add(New Task(AddressOf LongRunningInitialization2))
    tasks.Add(New Task(AddressOf LongRunningInitialization3))
    tasks.Add(New Task(AddressOf LongRunningInitialization4))
    tasks.Add(New Task(AddressOf LongRunningInitialization5))
    tasks.Add(New Task(AddressOf LongRunningInitialization6))
    tasks.Add(New Task(AddressOf LongRunningInitialization7))
    ' Start all tasks.
    tasks.All(
        Function(t As Task)
            t.Start()
            Return True
        End Function
    )
    ' Wait until all tasks has been finished.
    While tasks.Any(Function(t As Task) Not (t.Status = TaskStatus.Canceled OrElse t.Status = TaskStatus.Faulted OrElse t.Status = TaskStatus.RanToCompletion))
        Application.DoEvents()
        Sleep(1)
    End While
End Sub