1. ホーム
  2. c#

[解決済み] await は動作するが、task.Result を呼び出すとハングアップ/デッドロックする。

2022-05-16 22:19:24

質問

以下の4つのテストがありますが、最後の1つは実行するとハングアップしてしまいます。なぜこのようなことが起こるのでしょうか。

[Test]
public void CheckOnceResultTest()
{
    Assert.IsTrue(CheckStatus().Result);
}

[Test]
public async void CheckOnceAwaitTest()
{
    Assert.IsTrue(await CheckStatus());
}

[Test]
public async void CheckStatusTwiceAwaitTest()
{
    Assert.IsTrue(await CheckStatus());
    Assert.IsTrue(await CheckStatus());
}

[Test]
public async void CheckStatusTwiceResultTest()
{
    Assert.IsTrue(CheckStatus().Result); // This hangs
    Assert.IsTrue(await CheckStatus());
}

private async Task<bool> CheckStatus()
{
    var restClient = new RestClient(@"https://api.test.nordnet.se/next/1");
    Task<IRestResponse<DummyServiceStatus>> restResponse = restClient.ExecuteTaskAsync<DummyServiceStatus>(new RestRequest(Method.GET));
    IRestResponse<DummyServiceStatus> response = await restResponse;
    return response.Data.SystemRunning;
}


私はこの拡張メソッドを使って restsharp RestClient :

public static class RestClientExt
{
    public static Task<IRestResponse<T>> ExecuteTaskAsync<T>(this RestClient client, IRestRequest request) where T : new()
    {
        var tcs = new TaskCompletionSource<IRestResponse<T>>();
        RestRequestAsyncHandle asyncHandle = client.ExecuteAsync<T>(request, tcs.SetResult);
        return tcs.Task;
    }
}

public class DummyServiceStatus
{
    public string Message { get; set; }
    public bool ValidVersion { get; set; }
    public bool SystemRunning { get; set; }
    public bool SkipPhrase { get; set; }
    public long Timestamp { get; set; }
}

なぜ最後のテストはハングアップするのでしょうか?

どのように解決するのですか?

私が説明した標準的なデッドロックの状況に陥っています。 ブログで は、MSDN の記事で async メソッドの呼び出しによってブロックされているスレッドに その継続をスケジュールしようとしています。 Result .

この場合、あなたの SynchronizationContext は、NUnit が実行する async void テストメソッドを実行するために使用されるものです。私なら async Task テストメソッドを使うようにします。