web-dev-qa-db-ja.com

待つことなく非同期メソッドを呼び出す#2

私は非同期メソッドを持っています:

public async Task<bool> ValidateRequestAsync(string userName, string password)
{
    using (HttpClient client = new HttpClient())
    {
        HttpResponseMessage response = await client.GetAsync(url);
        string stringResponse = await response.Content.ReadAsStringAsync();

        return bool.Parse(stringResponse);
    }
}

このメソッドを次のように呼び出します。

bool isValid = await ValidateRequestAsync("user1", "pass1");

awaitキーワードを使用せずに、同期メソッドから同じメソッドを呼び出すことはできますか?

例:

public bool ValidateRequest(string userName, string password)
{
    return ValidateRequestAsync(userName, password).Result;
}

これはデッドロックを引き起こすと思います。

[〜#〜] edit [〜#〜]

上記のようなメソッドを呼び出すと、呼び出しは終了しません。 (メソッドはもう終わりに達していません)

40
Catalin

UIスレッドなどのシングルスレッド実行コンテキストから非同期メソッドを呼び出し、結果を同期的に待機すると、デッドロックが発生する可能性が高くなります。あなたの例では、その確率は100%です

考えてみてください。電話をかけるとどうなりますか

ValidateRequestAsync(userName, password).Result

メソッドValidateRequestAsyncを呼び出します。そこで、ReadAsStringAsyncを呼び出します。その結果、タスクはUIスレッドに返され、UIスレッドが使用可能になったときに実行を継続するようにスケジュールされます。しかし、もちろん、タスクが完了するのを待っている(ブロックされている)ため、使用可能になることはありません。しかし、UIスレッドが使用可能になるのを待っているため、タスクは終了できません。デッドロック。

このデッドロックを防ぐ方法はありますが、それらはすべて悪い考えです。完全を期すために、以下が機能する可能性があります。

Task.Run(async () => await ValidateRequestAsync(userName, password)).Result;

UIスレッドが待機していて、何も役に立たないのをブロックするため、これは悪い考えです。

それでは、解決策は何ですか?ずっと非同期にしてください。 UIスレッドの元の呼び出し元はおそらくイベントハンドラーであるため、非同期であることを確認してください。

63

return ValidateRequestAsync(userName、password).GetAwaiter()。GetResult();を使用できます。

5
savagepanda