阻塞与非阻塞异步代码

Blocking vs Non Blocking Asynchronous code

我正在对一些已经编写的旧代码进行自我审查,想知道以下代码是否以任何方式阻塞了当前线程或者它一直都是非阻塞的?

根据 Microsoft 的建议,我对所有应用程序使用单个 HttpClient 实例

HttpClient is intended to be instantiated once and re-used throughout the life of an application. Instantiating an HttpClient class for every request will exhaust the number of sockets available under heavy loads. This will result in SocketException errors.https://docs.microsoft.com/en-us/dotnet/api/system.net.http.httpclient?view=netframework-4.8#remarks

public virtual async Task<Tuple<string, bool>> PostAsync(string resourceUrl, string body, string basicToken)
{
    string methodName = "PostAsync";
    var response = new Tuple<string, bool>(string.Empty, false);
    try
    {
        var content = new StringContent(body, Encoding.UTF8, "application/json");
        var request = new HttpRequestMessage(HttpMethod.Post, resourceUrl);
        request.Headers.Add("Authorization", basicToken);
        request.Content = new StringContent(body, Encoding.UTF8, "application/json");
        var httpResponse = await ApplicationWrapper.AccessTokenClient.SendAsync(request).ConfigureAwait(false);
        response = new Tuple<string, bool>(await httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false), httpResponse.IsSuccessStatusCode);
    }
    catch (WebException e)
    {
        Util.Log(methodName + " | WebException: " + e.Message + "|" + e.StackTrace.ToString());
        using (WebResponse WebResponse = e.Response)
        {
            HttpWebResponse httpResponse = (HttpWebResponse)WebResponse;
            using (var streamReader = new StreamReader(WebResponse.GetResponseStream()))
                Util.Log(methodName + " | Exception postAsync API: " + streamReader.ReadToEnd());
        }
    }
    catch (Exception ex)
    {
        Util.Log(methodName + " | Exception: " + ex.Message + "|" + ex.StackTrace.ToString() + "|" + ex.InnerException);
    }


    return response;
}

Microsoft 声明 ReadAsStringAsync 的事实

This operation will not block. https://docs.microsoft.com/en-us/dotnet/api/system.net.http.httpcontent.readasstringasync?view=netframework-4.8

此外,为了避免死锁,建议使用 ConfigureAwait(false)

ConfigureAwait(false) configures the task so that continued after the await does not have to be run in the caller context, therefore avoiding any possible deadlocks. https://medium.com/bynder-tech/c-why-you-should-use-configureawait-false-in-your-library-code-d7837dce3d7f

压力下的阻塞异步代码会影响服务器,CPU 随着线程数量不断增加,利用率达到 90% ... 上面的代码中是否有任何方面是阻塞的?

我觉得这一切都很好。一个简单的经验法则是,如果您在异步方法的 return 值 (Task) 上看到任何 .Result.Wait() 的出现,那么您将阻塞 可能 应该 awaiting。在这里看不到 - 您似乎正在等待所有异步调用。现在只要确保任何调用这个方法也是awaiting,一直到调用堆栈。如果你在任何地方阻塞,那一切都是徒劳的。 :)