VB.NETの「非同期処理」を制する:BackgroundWorkerからの卒業と、現代的アプローチへの進化
こんにちは。長年VB.NETと向き合ってきた皆さんに、今日は少しだけ「未来の話」をしましょう。
Windows Formsの現場で長らく愛されてきた`BackgroundWorker`。かつては非同期処理の代名詞でしたが、現代の.NET開発において、それは「レガシーな遺産」となりつつあります。なぜなら、私たちはもっと安全で、直感的で、そして何より「モダンな」制御を手に入れたからです。
今日は、`BackgroundWorker`を卒業し、`IProgress(Of T)`と`CancellationTokenSource`という、現代の非同期処理のスタンダードへ移行する極意を伝授します。ここを乗り越えれば、あなたの書くVB.NETコードは一気にプロフェッショナルな品質へと飛躍しますよ。
—
1. なぜ「BackgroundWorker」を卒業するのか?
`BackgroundWorker`は便利でしたが、実は「イベントベース」の非同期処理ゆえに、コードが断片的になりがちでした。処理の開始、進捗報告、完了、そしてキャンセルの制御が別々のイベントハンドラに散らばり、処理の流れ(ロジック)を追うのが非常に困難だったはずです。
現代の `Async / Await` パターンは、非同期処理をまるで同期処理を書くかのように直感的に記述できます。
—
2. 移行の要:3つの主要パーツ
モダンな非同期処理を構成するのは以下の3つです。
1. `Task`: 処理そのものの単位。
2. `IProgress(Of T)`: 安全にUIへ進捗を報告するメッセンジャー。
3. `CancellationTokenSource`: 非同期処理を任意のタイミングで停止させる司令塔。
—
3. 実装コード:モダンな非同期処理の書き方
では、実際にボタンを押して重い処理を実行し、途中でキャンセル可能なサンプルを見てみましょう。
Imports System.Threading
Imports System.Threading.Tasks
Public Class MainForm
‘ キャンセルを制御する司令塔
Private _cts As CancellationTokenSource
Private Async Sub btnStart_Click(sender As Object, e As EventArgs) Handles btnStart.Click
‘ 前回のキャンセル操作をリセット
_cts = New CancellationTokenSource()
‘ 進捗をUIに伝えるためのProgressオブジェクト
‘ UIスレッドへのマーシャリングはIProgressが自動でやってくれます
Dim progress = New Progress(Of Integer)(Sub(percent)
ProgressBar1.Value = percent
LabelStatus.Text = $”進捗: {percent}%”
End Sub)
Try
‘ 非同期処理の開始
Await Task.Run(Function() DoWork(progress, _cts.Token))
MessageBox.Show(“処理が完了しました!”)
Catch ex As OperationCanceledException
MessageBox.Show(“処理はキャンセルされました。”)
Finally
_cts.Dispose()
_cts = Nothing
End Try
End Sub
‘ 実際の重い処理(別スレッドで動作)
Private Sub DoWork(progress As IProgress(Of Integer), token As CancellationToken)
For i As Integer = 1 To 100
‘ ここでキャンセル指示が来ていないかチェック
token.ThrowIfCancellationRequested()
‘ 重い処理のシミュレーション
Thread.Sleep(50)
‘ 進捗を報告
progress.Report(i)
Next
End Sub
‘ キャンセルボタンのイベント
Private Sub btnCancel_Click(sender As Object, e As EventArgs) Handles btnCancel.Click
_cts?.Cancel() ‘ キャンセル信号を送る
End Sub
End Class
—
4. なぜこの書き方が「最強」なのか?
① UIスレッドへの安全なアクセス
`BackgroundWorker`では、進捗を報告する際に `Control.Invoke` を意識する必要がありましたが、`Progress(Of T)` を使えば、その制御を自動的に行ってくれます。つまり、「スレッドセーフ」なコードが非常に簡単に書けるのです。
② キャンセルの明確な意図
`CancellationToken` をメソッドに渡すことで、「どこでキャンセルチェックを行うか」を明確に制御できます。`token.ThrowIfCancellationRequested()` は非常にエレガントで、例外機構を利用して処理を即座に中断させます。
③ 可読性の向上
処理の開始から終了までが、一つの `Async Sub` の中に記述されています。コードが上から下に流れるため、後からメンテナンスする際も「何がどこで起きているか」が一目瞭然です。
—
最後に:一歩ずつ進めば必ず到達できる
最初は `Async` や `Await` という単語に戸惑うかもしれません。「なぜ別スレッドなのに同じ場所に書けるの?」と不思議に思うでしょう。
でも、安心してください。「重い処理は `Task.Run` で囲み、UIへの通知は `IProgress` に任せる」。このパターンさえ覚えてしまえば、あなたのVB.NETスキルはもう初学者レベルではありません。
現場で「BackgroundWorkerを使おうとしている人がいたら、優しくこのパターンを教えてあげてください。それが、モダンなVB.NETエンジニアとしての最初の一歩です。
皆さんのコーディングが、より美しく、そして効率的なものになることを心から応援しています!
