C#におけるasync/awaitを使用した非同期プログラミングは、UIのフリーズ防止やI/O処理(ファイル、ネットワーク)の効率化に不可欠です。
最新の標準的な書き方と、押さえておくべきポイントを整理しました。
1. 基本的な構文
非同期メソッドを定義するには、メソッドに async 修飾子を付け、戻り値を Task または Task<T> にします。
C#
// 非同期メソッドの定義
public async Task<string> GetDataAsync(string url)
{
using var client = new HttpClient();
// 非同期処理を待機(await)
// awaitしている間、スレッドは解放され、他の処理が可能になる
string result = await client.GetStringAsync(url);
return result;
}
重要なルール
- 戻り値: 値を返さない場合は
Task、値を返す場合はTask<T>を使用します。 - 命名規則: メソッド名の末尾には
Asyncを付けるのが一般的です。 - await: 非同期処理の結果が必要な箇所で
awaitを呼び出します。
2. 非同期処理の制御フロー
await キーワードに到達すると、メソッドの実行は一時停止し、制御が呼び出し元に戻ります。バックグラウンドでの処理が完了すると、続きから実行が再開されます。
3. 複数の非同期処理を並列で実行する
複数の処理を一つずつ待つのではなく、同時に開始してすべて終わるのを待つことでパフォーマンスが向上します。
C#
var task1 = DoWork1Async();
var task2 = DoWork2Async();
// 両方のタスクが完了するまで待機
await Task.WhenAll(task1, task2);
// 結果を受け取る場合
var results = await Task.WhenAll(GetVal1Async(), GetVal2Async());
4. キャンセル処理 (CancellationToken)
最新のC#では、途中で処理を中断できるように CancellationToken を渡すのがマナーです。
C#
public async Task DownloadFileAsync(string url, CancellationToken ct)
{
using var client = new HttpClient();
// キャンセルされた場合に例外を投げる
var response = await client.GetAsync(url, ct);
// または手動でチェック
ct.ThrowIfCancellationRequested();
}
5. 推奨されるベストプラクティス
| 項目 | 推奨される書き方 | 避けるべき書き方 |
| 待機方法 | await task; | task.Wait() や task.Result (デッドロックの原因) |
| 戻り値 | async Task | async void (例外ハンドリングができなくなるため) |
| 例外処理 | try-catch で await を囲む | 例外を無視する |
| 最適化 | 短時間で終わる場合は ValueTask | 全てに ValueTask を使う (複雑化を避ける) |
補足:ValueTask について
高頻度で呼び出され、かつ多くの場合で即座に完了する(非同期にする必要がない場合がある)処理には、メモリ負荷を抑えるために ValueTask<T> を検討してください。
6. 例外ハンドリング
非同期メソッド内での例外は、await したタイミングでキャッチできます。
C#
try
{
await SomeAsyncWork();
}
catch (HttpRequestException ex)
{
Console.WriteLine($"ネットワークエラー: {ex.Message}");
}
非同期処理は、歴史的に色々な書き方があり、なかなか理解するのが難しかったのですが、async/awaitにより、簡単に扱えるものになりました。実はこれコンパイル技術の賜物なのです。


最近のコメント