C# 基礎からマスターまで — 第8回
asyncとawaitで非同期ジョブを構成する
本ブログ作成文は、講義を目指して製作されました。 また、作成された文章の情報も間違っている可能性がありますので、ご注意ください。
ネットワークやファイルの操作を待っている間にスレッドをブロックすると、画面や他の作業も停止することがあります。 asyncとawaitは、待ち時間のあるタスクを引き続き実行できるように表現します。
タスクを返す
async Task<PlayerData> LoadPlayerAsync(
string url,
CancellationToken cancellationToken)
{
using HttpResponseMessage response =
await httpClient.GetAsync(url, cancellationToken);
response.EnsureSuccessStatusCode();
PlayerData? data = await response.Content
.ReadFromJsonAsync<PlayerData>(cancellationToken);
return data ?? throw new InvalidDataException("Player data is empty");
}
awaitに会えば、作業が終わるまで現在のスレッドを保持し続けるのではなく、残りのコードを後で続けることができます。 asyncメソッドは、呼び出し元が完了と失敗を観察できるようにTaskを返すことが基本です。
キャンセルを転送する
using var source = new CancellationTokenSource(TimeSpan.FromSeconds(5));
try
{
PlayerData data = await LoadPlayerAsync(url, source.Token);
}
catch (OperationCanceledException)
{
Console.WriteLine("Loading canceled");
}
キャンセルはスレッドを強制的に終了する機能ではありません。 タスクがトークンを確認し、安全なポイントで中断するように要求する契約です。
複数のジョブを待つ
Task<ItemData> itemTask = LoadItemsAsync(token);
Task<QuestData> questTask = LoadQuestsAsync(token);
await Task.WhenAll(itemTask, questTask);
ItemData items = await itemTask;
QuestData quests = await questTask;
互いに依存しない待機タスクは、最初に開始してから一緒に待つことができます。 CPU計算を単にasyncとしてマークすると自動的に並列化されません。
避けるべき流れ
Taskの.Resultや.Wait()で同期待機すると、スレッドをブロックしたり、実行環境に応じてデッドロックを作成することができる。 呼び出しパスをできるだけ最後までasyncにつながるほうがいい。
async voidは、呼び出し元が完了と例外を待つことができないため、イベントハンドラ以外には避けてください。 非同期コードの鍵は、キーワードを付けるのではなく、完了、失敗、キャンセルの流れをすべて呼び出し元に渡すことです。