こんにちは。弱小エンジニアのいすいです。
最近仕事でコードのリファクタリングを行っていて、
その中でTaskの使い方を再認識したので、今回まとめてみました。
Taskを使うべき場所
引き継いだコードでは至る所にTaskが散りばめられていました。
とりあえずTaskにしとこ!って前任者は考えていたのでしょう。。
当たり前ですが、非同期処理が必要ないところでTaskを使って非同期処理をしても意味がないので、非同期処理が必要な箇所に絞りました。
よくある非同期処理はファイル読み込みや、APIアクセス、DBアクセスなどのイメージですしたので、その辺りをリファクタしました。
awaitで待機するタイミング
戻り値がTask型だと、awaitで待機すると思いますが、
すぐにawaitで待たない方が良いなという時がありました。
それは複数の非同期処理をまとめて待機したい時です。
以下はコードの例です。
Task taskA = Task.Run(()=>
{
Thread.Sleep(3000);
});
Task taskB = Task.Run(()=>
{
Thread.Sleep(3000);
});
Task taskC = Task.Run(()=>
{
Thread.Sleep(3000);
});
// ここでまとめてawait
await Task.WhenAll(taskA, taskB, taskC);
こうすることで、taskA,taskB,TaskCを非同期で処理できます。
awaitの階層
awaitの中でawaitした時どうなるのか混乱したのでまとめました。
awaitしている処理の中でさらにawaitをすると、メインスレッドに呼び出し元が戻ります。
例えば以下の場合、
void MethodA()
{
MethodB();
Console.WriteLine("A");
}
async void MethodB()
{
await MethodC();
Console.WriteLine("B");
}
async Task MethodC()
{
await Task.Run(()=>
{
Thread.Sleep(3000);
Console.WriteLine("C");
});
}
実行すると、
A
C
B
の順番で出力されます。
MethodCで3秒スリープしている間に、
MethodAがメインスレッドで処理を進め、
MethodCが完了したあと、
MethodBが最後まで実行されます。
ちなみに、MethodCの処理中にMethodAの処理は完了してしまうことになります。
処理Aの中でawaitするとその先の処理A自体は止まってしまうので、
awaitの先も待たずに処理したい場合には処理Aの中でawaitを読んではいけないので、全てawaitで呼び出すというわけでもないのです。
async voidはだめ?
ネットにはasync voidは使わないほうが良いという記事があったりするのですが、
個人的にはasync voidを使って良いと思っています🧐🧐🧐
損はないからasync Taskにしとけってことですかね。。
でもTaskをawaitで呼ばない時、VisualStudioでawaitがないよって言われちゃうんですけどね。(エラーにはならないけど)
他にはTask.Wait()はデッドロックのリスクがあるので、しない方がいいみたいですね。
あまり良く理解していませんが、これはとりあえずしないように気をつけとこうと思います。
Taskを入れ子にしても意味ない
引き継いだコードには、Taskが入れ子のようになっているものがありました。
例えば以下のようなものです。
async void MethodA()
{
await Task.Run(async ()=>
{
await MethodB();
});
}
async Task MethodB()
{
await Task.Run(()=>
{
Thread.Sleep(3000);
});
}
awaitしている間は受け待ちになるので、以下のコードと同じです。
async void MethodA()
{
await Task.Run(()=>
{
Thread.Sleep(3000);
}
}
状況によりけりなのでどれが良いとか断言できないですが、できるだけ無駄なことは避けたいところです。
Taskを正確に使えるようにまだまだ頑張ります。
How is the COVID situation over there?
Leave me alone, I’m just taking a look
Have an upvote. And a comment mostly so I can find this thread easily and study from time to time. Refreshers never hurt. Thank you!
Happy everyday!