async/await 非同期メソッドの待ちかた
async/awaitを使うと数珠繋ぎでasync/awaitが連鎖しがち。
そんな時に非同期処理を同期として呼び出したい場合に以下の2パターンが多い様子。。
- task.GetAwaiter().GetResult()
- task.Wait()
例外で差分があるようなので比較した。
Wait()
ソース
namespace Sandbox
{
using System;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
try
{
Console.WriteLine($"{DateTime.Now} start");
Task.Run(HeavyFunctionAsync).Wait();
Console.WriteLine($"{DateTime.Now} end");
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
public static async Task HeavyFunctionAsync()
{
for (var i = 0; i < 5; i++)
{
await Task.Delay(1000);
Console.WriteLine($"{DateTime.Now} N={i}");
}
throw new InvalidOperationException("exception");
return;
}
}
}
結果
AggregrateExceptinoとして捕捉。InnerException見る必要があるのがメンドクサイ。
2021/06/05 21:30:30 start
2021/06/05 21:30:32 N=0
2021/06/05 21:30:33 N=1
2021/06/05 21:30:34 N=2
2021/06/05 21:30:35 N=3
2021/06/05 21:30:36 N=4
System.AggregateException: One or more errors occurred. (exception)
---> System.InvalidOperationException: exception
at Sandbox.Program.HeavyFunctionAsync() in D:\work\Repos\Sandbox\Sandbox\Program.cs:line 30
--- End of inner exception stack trace ---
at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
at System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout, CancellationToken cancellationToken)
at System.Threading.Tasks.Task.Wait()
at Sandbox.Program.Main(String[] args) in D:\work\Repos\Sandbox\Sandbox\Program.cs:line 13
GetAwaiter().GetResult()
ソース。
namespace Sandbox
{
using System;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
try
{
Console.WriteLine($"{DateTime.Now} start");
Task.Run(HeavyFunctionAsync).GetAwaiter().GetResult();
Console.WriteLine($"{DateTime.Now} end");
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
public static async Task HeavyFunctionAsync()
{
for (var i = 0; i < 5; i++)
{
await Task.Delay(1000);
Console.WriteLine($"{DateTime.Now} N={i}");
}
throw new InvalidOperationException("exception");
return;
}
}
}
結果
InvalidOperationExceptionとして捕捉。
2021/06/05 21:27:48 start
2021/06/05 21:27:49 N=0
2021/06/05 21:27:50 N=1
2021/06/05 21:27:51 N=2
2021/06/05 21:27:52 N=3
2021/06/05 21:27:53 N=4
System.InvalidOperationException: exception
at Sandbox.Program.HeavyFunctionAsync() in D:\work\Repos\Sandbox\Sandbox\Program.cs:line 30
at Sandbox.Program.Main(String[] args) in D:\work\Repos\Sandbox\Sandbox\Program.cs:line 13
結論
Wait()は良くある別タスク内で発生した例外同様AggreateExceptinoでまとめてChatchされる。
一方でGetAwaiter().GetResult()は同期メソッドで例外が発生したかの如く、発生時の状態で補足される。
個人的にはGetAwaiter().GetResult()の方が好きだが別意見の人もいそう