LoginSignup
4

More than 3 years have passed since last update.

posted at

updated at

『応答なし』にならないアプリ開発 Part.2

既存処理の『応答なし』対策救世主?

前回はDoEvents・Win32API・BackgroundWorkerの説明を上げましたが、本題のTaskを簡単に紹介したいと思います。
TaskはBackgroundWorkerと違い、既存の処理に少し手を加えるだけで実装可能なので、すでに出来上がっているけど『応答なし』や実行中に固まってしまう事を解決したい・・・というときに活用できます。

まずは比較用に

まずは『応答なし』や実行中はフォームが固まってしまうプログラムです。

・Form1にボタン・プログレスバー・ラベルを一個ずつ配置

Form1.vb
Imports System.ComponentModel
Public Class Form1
    Private MAX_COUNT = 100

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
        ProgressBar1.Hide()
        Label1.Hide()
    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        ProgressBar1.Maximum = MAX_COUNT
        ProgressBar1.Value = 0
        ProgressBar1.Step = 1
        Label1.Text = String.Empty

        '*** 処理実施
        ProgressBar1.Show()
        Label1.Show()
        For i = 1 To MAX_COUNT
            WaitProcess()

            ProgressBar1.PerformStep()
            Label1.Text = String.Format("({0}/{1})", ProgressBar1.Value, MAX_COUNT)
        Next
        ProgressBar1.Hide()
        Label1.Hide()
    End Sub

    Private Sub WaitProcess()
        '*** 重い処理
        Threading.Thread.Sleep(500)
    End Sub
End Class

Task(Async/Await)化

上記プログラムをTaskを使用した形に書き換えます。

Form1.vb
Imports System.ComponentModel
Public Class Form1
    Private MAX_COUNT = 100

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
        ProgressBar1.Hide()
        Label1.Hide()
    End Sub

    Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        ProgressBar1.Maximum = MAX_COUNT
        ProgressBar1.Value = 0
        ProgressBar1.Step = 1
        Label1.Text = String.Empty

        '*** 処理実施
        ProgressBar1.Show()
        Label1.Show()
        For i = 1 To MAX_COUNT
            Await Task.Run(Sub()
                               WaitProcess()
                           End Sub)

            ProgressBar1.PerformStep()
            Label1.Text = String.Format("({0}/{1})", ProgressBar1.Value, MAX_COUNT)
        Next
        ProgressBar1.Hide()
        Label1.Hide()
    End Sub

    Private Sub WaitProcess()
        '*** 重い処理
        Threading.Thread.Sleep(500)
    End Sub
End Class

修正点は以下の二点になります。

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
       ↓
Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        For i = 1 To MAX_COUNT
            WaitProcess()
       ↓
        For i = 1 To MAX_COUNT
            Await Task.Run(Sub()
                               WaitProcess()
                           End Sub)
  • Taskを使用するメソッドに『Async』を追加
  • 重い処理を『Await Task.Run(Sub() 重い処理 End Sub)』でくくる

上記の書き換えのみで処理実行中の動作が変わったことが実感できます。

Task利用時の注意点

このように手軽に利用できそうなTaskですが、先のBackgroundWorker同様にマルチスレッドの処理になりますので、Task処理内でコントロールにアクセスする等そのままでは出来ません。
また、BackgroundWorker等と同様、各ボタンの非活性等で同時実行を制御する必要があります。

Taskについてはまた別にまとめていきたいと思います。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
4