WinodwsFormsアプリから学ぶ同期と非同期の違い
同期プログラミングと非同期プログラミングの違いを示すWindows Formsのサンプルを紹介します
同期と非同期
同期(Synchronous)とは、1つの処理が終了するまで、次の処理を開始することを待つことを意味します。同期処理では、処理中に他の処理を行えません。
非同期(Asynchronous)とは、1つの処理が終了するまで、次の処理を開始することを待たずに、他の処理を行えることを意味します。非同期処理は、同時に複数のタスクを実行することができ、ユーザーインターフェイスをフリーズさせないために使用されます。
次の例では、「同期実行ボタン」を押すと「重い処理」が同期的に実行されます。これにより、「重い処理」の実行中に他の処理を行えなくなり、ユーザーインターフェイスもフリーズします。一方、「非同期実行ボタン」を押すと「重い処理」が非同期的に実行されます。これにより、「重い処理」の実行中に他の処理を行えます。
テストアプリの動作
このアプリケーションは、「同期実行ボタン」と「非同期実行ボタン」、「色変更ボタン」の3つのボタンを持っています。
Form1
クラスは、Form
クラスを継承し、各ボタンに対応するイベントハンドラを定義しています。
「同期実行ボタン」を押すと、同期処理として「重い処理」が実行されます。この場合、「重い処理」が終了するまで、ユーザーインターフェイス(UI)スレッドはブロックされます。
「非同期実行ボタン」を押すと、非同期処理として「重い処理」が実行されます。この場合、「重い処理」は、別のバックグラウンドスレッドで実行され、UIスレッドはブロックされません。「重い処理」が終了した後、結果ラベルが更新されます。
「色変更ボタン」を押すたびに、ボタンの背景色がランダムに変更されます。
このコードは、同期処理と非同期処理の使い方を示す簡単な例です。
テストアプリの作成
実行した様子
フォームデザイン
画面デザインになります

テスト用のコード
コードの説明
Form1クラスは、WinFormsのフォームクラスを拡張しています。初期化メソッド(InitializeComponent)が呼び出され、「カラーチェンジボタン」の文字色が白に設定されます。
- SyncButton_Clickメソッドは、同期処理ボタンのイベントハンドラです。「同期処理を開始」というメッセージが表示され、「PerformHeavyTask」メソッドが呼び出されます。「PerformHeavyTask」メソッドが終了した後、「同期処理を終了」というメッセージが表示されます。
- AsyncButton_Clickメソッドは、非同期処理ボタンのイベントハンドラです。「非同期処理を開始」というメッセージが表示され、「PerformHeavyTaskAsync」メソッドが呼び出されます。「PerformHeavyTaskAsync」メソッドは、「PerformHeavyTask」メソッドを非同期で実行するために、Task.Runメソッドを使用します。「PerformHeavyTask」メソッドが終了した後、「非同期処理を終了」というメッセージが表示されます。
- PerformHeavyTaskメソッドは、重いタスクを実行するためのメソッドです。この例では、5秒間スリープするというシンプルなタスクが実行されます。
- PerformHeavyTaskAsyncメソッドは、非同期で「PerformHeavyTask」メソッドを実行するためのメソッドです。
- colorChangeButton_Clickメソッドは、ボタンを押すたびに背景色が変わるイベントハンドラです。このメソッドは、毎回新しいランダムな色を生成して、「colorChangeButton」の背景色を設定します。
実際に有効性のあるコードにするためには改善が必要
このコードについては以下の改善点が考えられます。
- 非同期メソッド
PerformHeavyTaskAsync
の戻り値:非同期メソッドは常にTask
オブジェクトを返す必要がありますが、このメソッドは戻り値がありません。このメソッドを非同期処理として使用する場合は、戻り値をTask
オブジェクトに変更する必要があります。 PerformHeavyTaskAsync
メソッドのasync
修飾子:このメソッドは非同期処理を行いますが、async
修飾子を使用することで明示的に非同期メソッドとしてマークすることができます。ResultLabel
の変更:このコードでは、同期処理と非同期処理でResultLabel
のテキストを変更するという処理がありますが、複数のスレッドから同時にこのコントロールを変更することができるため、競合状態が発生する可能性があります。この問題を解決するためには、Invoke
メソッドを使用するなどの方法があります。
改善したコード
改善したコード(コメント付き)
改善点:
PerformHeavyTaskAsync
メソッドから返されるタスクを非同期に実行するためにawait
キーワードを使用するように更新しました。ColorChangeButton_Click
メソッド内で同時実行が可能な問題を回避するために、lock
ステートメントを使用しました。- ボタンのクリックハンドラー内での
ResultLabel.Text
の更新を、正しい位置に移動しました。 - 全体的にコードの構造をより読みやすく整理しました。
ディスカッション
コメント一覧
まだ、コメントがありません