非同期プログラミング入門 – C#での実装方法
C#では、async
/await
を使うことで、待機処理やバックグラウンドでの処理を簡単に実装できます。ここでは、非同期処理の基本的な考え方と、実際にコードを書くときのポイントについて解説します。
目次
1. 非同期処理の基本概念
- 非同期処理とは:
長い時間がかかる処理(例えば、ネットワーク通信やファイルアクセス)を実行中も、他の作業をブロックせずに並行して行える仕組みです。 - ブロックしない待機:
Task.Delay
のような非同期メソッドを利用すると、指定した時間だけ処理を「待つ」間も、他の作業を進めることができます。
2. async/awaitを使った非同期メソッド
基本の書き方
非同期メソッドを定義するには、async
キーワードを使い、返り値にTask
またはTask<T>
を指定します。
以下の例は、1秒ごとに繰り返し処理を行う非同期メソッドです。
using System;
using System.Threading.Tasks;
class Program
{
// Taskを返す非同期メソッド
static async Task ProcessWithDelayAsync()
{
for (int i = 0; i < 5; i++)
{
Console.WriteLine($"Iteration {i}: 処理を実行中...");
await Task.Delay(1000); // 1秒待機
}
Console.WriteLine("非同期処理完了");
}
}
メソッドのポイント
async
修飾子:
このキーワードを付けることで、メソッド内でawait
を使用できるようになります。await
キーワード:Task.Delay
などの非同期メソッドの完了を待機しながら、スレッドをブロックしません。
3. 戻り値の型と呼び出し方
async Task と async void
- async Task:
- 戻り値として
Task
を返します。 - 呼び出し元で
await
を利用して完了待ちができ、例外もキャッチしやすいです。
- 戻り値として
static async Task ProcessWithDelayAsync()
{
// 省略
}
- async void:
- 戻り値がなく、呼び出し元で待機できません。
- 主にイベントハンドラーなど、戻り値を必要としない場面で使用します。
static async void ProcessWithDelayVoid()
{
// 省略
}
呼び出し方の違い
非同期メソッドとして呼び出す
戻り値がTask
の場合、呼び出し元でawait
を使って待機するのが基本です。
static async Task CallerMethodAsync()
{
Console.WriteLine("CallerMethodAsync 開始");
await ProcessWithDelayAsync(); // 非同期処理の完了を待機
Console.WriteLine("CallerMethodAsync 完了");
}
static async Task Main(string[] args)
{
await CallerMethodAsync();
}
同期的に呼び出す方法
非同期メソッドを同期的に呼び出す場合、返されたTask
に対して.Wait()
や.GetAwaiter().GetResult()
を利用します。ただし、UIスレッドなどで使用するとデッドロックのリスクがあるので注意してください。
static void CallerMethod()
{
ProcessWithDelayAsync().Wait(); // 同期的に待機
// または
// ProcessWithDelayAsync().GetAwaiter().GetResult();
Console.WriteLine("CallerMethod 完了");
}
static void Main(string[] args)
{
CallerMethod();
}
async void の呼び出し
async void
の場合は、呼び出し側で待機することができないため、単に呼び出すだけになります。例外の捕捉も呼び出し側では行いにくいので、注意が必要です。
static async void ProcessWithDelayVoid()
{
for (int i = 0; i < 5; i++)
{
Console.WriteLine($"Iteration {i}: 処理を実行中...");
await Task.Delay(1000);
}
Console.WriteLine("非同期処理完了");
}
static void CallerMethodVoid()
{
ProcessWithDelayVoid();
Console.WriteLine("CallerMethodVoid 呼び出し完了");
}
static void Main(string[] args)
{
CallerMethodVoid();
}
4. 呼び出し元での await の必要性
async Task
の場合:await
を使うことで、非同期処理の完了を待機し、例外が発生した場合にも呼び出し元でキャッチ可能です。
※await
を使わないと、非同期処理の完了を待たずに次の処理が実行されるため、意図しない動作になる可能性があります。- 例:
static async Task CallerMethodAsync()
{
await ProcessWithDelayAsync();
// 非同期処理の完了後に実行されるコード
}
5. まとめ
- 非同期メソッドの定義:
async
キーワードとTask
を返すことで、非同期処理を記述できる。
例:static async Task ProcessWithDelayAsync()
- awaitの役割:
非同期メソッドの完了を待機し、他の処理をブロックせずに並行処理を可能にする。 - 戻り値の違い:
async Task
:呼び出し元でawait
が使え、例外処理も容易。async void
:主にイベントハンドラーで利用され、呼び出し元で待機ができない。
- 呼び出し方法:
- 非同期処理の場合は、基本的に
await
を使って処理の完了を待つ。 - 必要に応じて、同期的に呼び出す方法もあるが、デッドロックに注意。
- 非同期処理の場合は、基本的に
このガイドを参考に、C#で効果的な非同期プログラミングを実現してください。
ディスカッション
コメント一覧
まだ、コメントがありません