Task③

async/await

await

メソッド内でTaskの実行を非同期的に待機する場合、awaitキーワードを付与します。

var task = Task.Run(() => hoge(();
await task;

awaitした時点で、メソッドは待機状態となり、呼び出し元に処理が戻ります。
taskが完了するとメソッドが再開され、await以降の処理が行われます。
await以降に処理が存在しない場合、待機の必要がないため、awaitは不要です。

async

awaitキーワードを含むメソッドにはasyncキーワードを付与する必要があります。

private async {戻り値型} Hoge()
{
}

asyncなメソッドの戻り値型は以下のいずれかです。

Task
  • メソッドが何らかの値をreturnしない場合
  • 呼び出し元でtry/catchすることで例外処理可能

以下サンプルコードと実行結果です。

public static void Main(string[] args)
{
    AsyncTest();
    Console.WriteLine("AsyncTest Called");
    Console.ReadKey();
}

private static async Task AsyncTest()
{
    try
    {
        await AsyncTask();
    }
    catch (Exception e)
    {
        Console.WriteLine($"Message : {e.Message}");
    }

    Console.WriteLine("AsyncTest Complete");
}

private static async Task AsyncTask()
{
    await Task.Delay(1000);
    Console.WriteLine("AsyncTask Complete");
    throw new InvalidOperationException("Error in AsyncTask");
}
AsyncTest Called
AsyncTask Complete
Message : Error in AsyncTask
AsyncTest Complete
Task<T>
  • メソッドが何らかの値をreturnする場合
  • Tはreturnする値の型
  • 呼び出し元でtry/catchすることで例外処理可能

以下サンプルコードと実行結果です。 Main()の実装は同じです。

private static async Task AsyncTest()
{
    try
    {
        var result = await AsyncHasValueTask();
        Console.WriteLine(result);
    }
    catch (Exception e)
    {
        Console.WriteLine($"Message : {e.Message}");
    }

    Console.WriteLine("AsyncTest Complete");
}

private static async Task<string> AsyncHasValueTask()
{
    await Task.Delay(1000);
    // このコメントアウトを解除すると、AsyncTest()で例外メッセージだけ出力されます。
    //throw new InvalidOperationException("Error in AsyncHasValueTask");
    return "AsyncHasValueTask Complete";
}
AsyncTest Called
AsyncHasValueTask Complete
AsyncTest Complete
void
  • イベントハンドラーの場合
  • 呼び出し元でawaitできず、例外も検出できないため、上記以外の使用は避ける

以下サンプルコードと実行結果です。 Main()の実装は同じです。 例外は処理されず、コンソールに出力されます。

private static async Task AsyncTest()
{
    try
    {
        AsyncVoid(); // コンパイルエラーになるのでawaitできない
    }
    catch (Exception e)
    {
        Console.WriteLine($"Message : {e.Message}");
    }

    Console.WriteLine("AsyncTest Complete");
}

private static async void AsyncVoid()
{
    await Task.Delay(1000);
    Console.WriteLine("AsyncVoid Complete");
    throw new InvalidOperationException("Error in AsyncVoid");
}
AsyncTest Complete
AsyncTest Called
AsyncVoid Complete

Unhandled Exception: System.InvalidOperationException: Error in AsyncVoid
   at ProgrammingInCSharp_Async.Program.AsyncVoid() in C:\Users\maki8\Documents\Visual Studio 2017\Projects\ProgrammingInCSharp_Async\ProgrammingInCSharp_Async\Program.cs:line 53
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location where exception was thrown ---
   at System.Threading.ThreadPoolWorkQueue.Dispatch()