49438


ライブラリの中で非同期メソッドを呼ぶときは、`ConfigureAwait(false)`
を使用してデッドロックを回避する、と多くのサイトで書かれています。  
次のように待つ必要がない場合に関しても、`ConfigureAwait(false)` を使用するべきなのでしょうか？  
もちろん処理の内容によるとは思うのですが、判断の指針となるものがあれば教えていただきたいです。

[code]

    public static Task<HttpResponseMessage> PatchAsync(this HttpClient client, Uri requestUri, HttpContent content, CancellationToken cancellationToken)
    {
        var method = new HttpMethod("PATCH");
        var request = new HttpRequestMessage(method, requestUri) { Content = content };
    
        return client.SendAsync(request, cancellationToken);
    }
    
[/code]


CC BY-SA 4.0
2018-10-16T00:50:44.613
49324
2018-10-23T02:25:29.990
2018-10-23T02:25:29.990
28215
28215
question
c#
await する必要がない場合に「Task を返す」のと「await + ConfigureAwait(false) を使う」のはどちらが良いでしょうか


自己解決しました。

同様の質問がありました。  
[Return Task or await and
ConfigureAwait(false)](https://stackoverflow.com/questions/23536848/return-
task-or-await-and-configureawaitfalse)

これを踏まえて、私は次のように実装しようと思います。

  * 非同期メソッドの後に処理が必要なら `async Task` メソッドにする。必要なければ `Task` メソッドにする。
  * `async Task` メソッドにする場合は、`await` する非同期メソッドを `ConfigureAwait(false)` する。
  * `async Task` メソッドか `Task` メソッドかで、例外の伝播が変わることに留意する。 
    * `async Task`：メソッドを待機したタイミングで例外が発生する。
    * `Task`：メソッドを呼び出したタイミングで例外が発生する。

* * *

例外の発生タイミングについての補足です。  
次のメソッドを呼び出す場合を考えます。

[code]

    public static async Task With(int millisecondsDelay)
    {
        await Task.Delay(millisecondsDelay).ConfigureAwait(false);
    }
    
    public static Task Without(int millisecondsDelay)
    {
        return Task.Delay(millisecondsDelay);
    }
    
[/code]

直列で呼び出す場合は、同じ場所で例外が発生します。ただし、スタックトレースは異なります。

[code]

    // (1) With 直列
    try
    {
        await With(10);
        await With(-2); // ここで例外が発生
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex);
    }
    
    // (2) Without 直列
    try
    {
        await Without(10);
        await Without(-2); // ここで例外が発生
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex);
    }
    
[/code]

並列で呼び出す場合は、違う場所で例外が発生します。

[code]

    // (3) With 並列
    try
    {
        var task1 = With(10);
        var task2 = With(-2);
        await Task.WhenAll(task1, task2); // ここで例外が発生
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex);
    }
    
    // (4) Without 並列
    try
    {
        var task1 = Without(10);
        var task2 = Without(-2); // ここで例外が発生
        await Task.WhenAll(task1, task2);
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex);
    }
    
[/code]

[async／awaitで例外処理をするには？［C#／VB］](http://www.atmarkit.co.jp/ait/articles/1805/16/news018.html)の「複数のタスクを並列実行したとき、発生した全ての例外を知るには？」で紹介されている方法では
(4) の場合に対応できないため、(3) と (4) 両方に対応できるように次のようにするのが良さそうです。

[code]

    var all = null as Task;
    try
    {
        var task1 = With(-10);
        var task2 = With(-2);
        all = Task.WhenAll(task1, task2);
        await all;
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex);
        if (all != null)
        {
            foreach (var innerEx in all.Exception.InnerExceptions)
            {
                Console.WriteLine($"[InnerExceptions]");
                Console.WriteLine(innerEx);
            }
        }
    }
    
[/code]


CC BY-SA 4.0
2018-10-19T06:24:20.687
49438
2018-10-21T23:46:21.357
2018-10-21T23:46:21.357
28215
28215
49324
answer