web服务性能/吞吐量的异步方法

本文关键字:吞吐量 异步方法 性能 服务 服务性 web | 更新日期: 2023-09-27 18:27:09

我正试图弄清楚在使用HttpClient向外部api POST时,使用aysnc/await是否有助于提高应用程序吞吐量。

场景:我有一个类,将POST的数据发送到支付处理器的web api。POST付款有4个步骤:1-POST联系人2-POST事务3-捐赠后4-POST信用卡支付

步骤1-4必须按照上面指定的顺序进行。

在等待支付处理器的响应时,我的应用程序没有任何"繁忙的工作"要做——在这种情况下,使用async/await进行以下操作有意义吗?它会在高容量期间提高应用程序吞吐量吗?谢谢

编辑:(问题标记为不清楚)1.我的应用程序是一个web api(微服务)2.我使用.Result(阻塞)来避免异步/等待(显然这是错误的!)3.我们将有1000 req/分钟的"尖峰"负载

    public virtual ConstituentResponse PostConstituent(Constituent constituent)
    {
        var response =  PostToUrl<Constituent>("/api/Constituents", constituent);
        if (!response.IsSuccessStatusCode)
            HandleError(response);
        return response.Content.ReadAsAsync<ConstituentResponse>().Result;
    }
    public virtual TransactionResponse PostTransaction(Transaction transaction)
    {
        var response = PostToUrl<Transaction>("/api/Transactions", transaction);
        if (!response.IsSuccessStatusCode)
            HandleError(response);
        return response.Content.ReadAsAsync<TransactionResponse>().Result;
    }
    public virtual DonationResponse PostDonation(Donation donation)
    {
        var response = PostToUrl<Donation>("/api/Donations", donation);
        if (!response.IsSuccessStatusCode)
            HandleError(response);
        return response.Content.ReadAsAsync<DonationResponse>().Result;
    }
    public virtual CreditCardPaymentResponse PostCreditCardPayment(CreditCardPayment creditCardPayment)
    {
        var response = PostToUrl<CreditCardPayment>("/api/CreditCardPayments", creditCardPayment);
        if (!response.IsSuccessStatusCode)
            HandleError(response);
        return response.Content.ReadAsAsync<CreditCardPaymentResponse>().Result;
    }
    protected virtual HttpResponseMessage PostToUrl<T>(string methodUri, T value)
    {
        return _httpClient.PostAsJsonAsync(methodUri, value).Result;
    }

上面的五个方法是从另一个类/函数调用的:

public virtual IPaymentResult Purchase(IDonationEntity donation, ICreditCard creditCard)
    {
        var constituentResponse = PostConstituent(donation);
        var transactionResponse = PostTransaction(donation, constituentResponse);
        var donationResponse = PostDonation(donation, constituentResponse, transactionResponse);
        var creditCardPaymentResponse = PostCreditCardPayment(donation, creditCard, transactionResponse);
        var paymentResult = new PaymentResult
        {
            Success = (creditCardPaymentResponse.Status == Constants.PaymentResult.Succeeded),
            ExternalPaymentID = creditCardPaymentResponse.PaymentID,
            ErrorMessage = creditCardPaymentResponse.ErrorMessage
        };
        return paymentResult;
    }

web服务性能/吞吐量的异步方法

不能在此处实际使用await Task.WhenAll,因为您在购买下一个异步操作时依赖于上一个操作的结果。因此,需要以序列化的方式执行它们。然而,仍然强烈建议您将async / await用于此类I/O,即。;web服务调用。

该代码是在消耗Async*方法调用的情况下编写的,但实际上并没有使用该模式——它是阻塞的,可能会导致死锁以及不希望的性能影响。您应该只在控制台应用程序中使用.Result(和.Wait())。理想情况下,您应该使用async / await。以下是调整代码的正确方法。

public virtual async Task<ConstituentResponse> PostConstituenAsync(Constituent constituent)
{
    var response = await PostToUrlAsync<Constituent>("/api/Constituents", constituent);
    if (!response.IsSuccessStatusCode)
        HandleError(response);
    return await response.Content.ReadAsAsync<ConstituentResponse>();
}
public virtual async Task<TransactionResponse PostTransactionAsync(Transaction transaction)
{
    var response = await PostToUrl<Transaction>("/api/Transactions", transaction);
    if (!response.IsSuccessStatusCode)
        HandleError(response);
    return await response.Content.ReadAsAsync<TransactionResponse>();
}
public virtual async Task<DonationResponse> PostDonationAsync(Donation donation)
{
    var response = await PostToUrl<Donation>("/api/Donations", donation);
    if (!response.IsSuccessStatusCode)
        HandleError(response);
    return await response.Content.ReadAsAsync<DonationResponse>();
}
public virtual async Task<CreditCardPaymentResponse> PostCreditCardPaymentAsync(CreditCardPayment creditCardPayment)
{
    var response = await PostToUrlAsync<CreditCardPayment>("/api/CreditCardPayments", creditCardPayment);
    if (!response.IsSuccessStatusCode)
        HandleError(response);
    return await response.Content.ReadAsAsync<CreditCardPaymentResponse>();
}
protected virtual Task<HttpResponseMessage> PostToUrlAsync<T>(string methodUri, T value)
{
    return _httpClient.PostAsJsonAsync(methodUri, value);
}

用法

public virtual await Task<IPaymentResult> PurchaseAsync(IDonationEntity donation, ICreditCard creditCard)
{
    var constituentResponse = await PostConstituentAsync(donation);
    var transactionResponse = await PostTransactionAsync(donation, constituentResponse);
    var donationResponse = await PostDonationAsync(donation, constituentResponse, transactionResponse);
    var creditCardPaymentResponse = await PostCreditCardPaymentAsync(donation, creditCard, transactionResponse);
    var paymentResult = new PaymentResult
    {
        Success = (creditCardPaymentResponse.Status == Constants.PaymentResult.Succeeded),
        ExternalPaymentID = creditCardPaymentResponse.PaymentID,
        ErrorMessage = creditCardPaymentResponse.ErrorMessage
    };
    return paymentResult;
}

首先,现在编写代码的方式根本没有帮助,因为您一直在通过调用Result进行阻塞。如果这是一件好事,为什么不让所有API都在内部为您做这件事呢?!你不能用async作弊。。。

只有当您超过线程池的能力时,您才会看到吞吐量的提高,这种情况发生在100个线程的范围内。

所需的平均线程数为CCD_ 8。插入一些数字,看看这对你来说是否现实。

我会把我关于是同步还是异步的标准帖子链接给你,因为我觉得你不清楚什么时候异步IO是合适的。

https://stackoverflow.com/a/25087273/122718为什么EF 6教程使用异步调用?https://stackoverflow.com/a/12796711/122718我们是否应该默认切换为使用异步I/O?

一般来说,当等待时间很长并且有许多并行请求在运行时,这是合适的。

我的应用程序在等待响应时没有任何"繁忙的工作"要做

收到的其他请求都是繁忙的工作。

请注意,当线程被阻塞时,CPU也不会被阻塞。另一个线程可以运行。

当你进行async/await时,你应该全天异步。阅读Async/Await-异步编程的最佳实践

你需要让他们返回异步

 public virtual async Task ConstituentResponse PostConstituent(Constituent constituent)
{
    var response =  PostToUrl<Constituent>("/api/Constituents", constituent);
    if (!response.IsSuccessStatusCode)
        HandleError(response);
    return await response.Content.ReadAsAsync<ConstituentResponse>();
}
//...
//etc

然后从主功能

  await Task.WhenAll(constituentResponse, transactionResponse, donationResponse, creditCardPaymentResponse);

编辑:读错操作。不要使用等待任务。WhenAll用于同步调用