Taskクラスを使用して非同期処理をする際、同期をとるためのタスク待ちについて記載します。

ここでは、非同期の処理待ちをする事ができる Async & AWait  と Wait()メソッドを説明します。

プログラムを起動したときのメインタスクは、UIタスク(ユーザインターフェースタスク)で、Taskクラスで起動するタスクは、ローカルタスクと以下記載します。

Async と AWait でのタスク待ち

GUIでボタンを押して重たい処理する場合を例にします。

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    System.Threading.Thread.Sleep(10000)     '重たい処理
End Sub

以上の処理を実行すると、処理が終了するまで、フォーム移動などの操作が出来なくなります。

次にTaskクラスを使用して処理を実行します。

Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    DirectCast(sender, Button).Enabled = False        'ボタンを選択できないようにする

    Dim task As Task = Task.Run(
        Sub()
            System.Threading.Thread.Sleep(10000)      '重たい処理
        End Sub
    )
    Await task                                        '処理が完了するのを非同期的に待つ

    MessageBox.Show("Task End")

    DirectCast(sender, Button).Enabled = True
End Sub

Async & Await の非同期メソッドで、UIスレッドに同期的な継続処理に自動変換されます。

上記では、ローカルタスクで処理が実行されるので、ボタンの選択は処理が終わるまで出来ませんが、フォームの操作は出来ます。

Await で処理を止めているのではなく、非同期的に待っているので、UIタスクに処理を戻します。

ローカルタスクでの処理が終了したら、MessageBox.Show(“Task End”)が実行されます。

上記のコードの省略化

Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    DirectCast(sender, Button).Enabled = False        'ボタンを選択できないようにする

    Await Task.Run(
        Sub()
            System.Threading.Thread.Sleep(10000)      '重たい処理
        End Sub
    )
    MessageBox.Show("Task End")

    DirectCast(sender, Button).Enabled = True
End Sub

戻り値がある場合

Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    DirectCast(sender, Button).Enabled = False        'ボタンを選択できないようにする

    Dim result As Boolean = Await Task.Run(
        Function() As Boolean
            System.Threading.Thread.Sleep(5000)
            Return True
        End Function
    )
    MessageBox.Show("Task End")

    DirectCast(sender, Button).Enabled = True
End Sub

・Task.Run()の場合は、Task(Of)の戻り値になります。

・Await Task.Run()の場合は、指定した戻り値になります。

 

Waitメソッドでの処理待ち

GUIで Wait() メソッドを使用することは、通常ありません。

以下のようにCUIの時、Awaitをおこなっても処理が終了しまう場合、に使用します。

Imports System.Threading

Module Module1

    Sub Main()
        Dim task As Task = Task.Run(
            Sub()
                System.Threading.Thread.Sleep(5000)      '重たい処理
                Console.WriteLine("Task End")
            End Sub
        )
        task.Wait()

        Console.WriteLine("End")
    End Sub

End Module