我试图弄清楚当使用HttpClient POST到外部api时,使用aysnc / await是否有助于应用程序吞吐量。
场景:我有一个类将POST数据发送到支付处理器web api。发布付款有4个步骤: 1 - POST联系人 2 - POST交易 3 - 后捐款 4 - POST信用卡付款
步骤1 - 4必须按照上面指定的顺序进行。
我的申请没有任何繁忙的工作"在等待来自支付处理器的响应时要做 - 在这种情况下,使用async / await进行下面的操作有意义吗?是否会在高容量期间提高应用程序吞吐量谢谢!
编辑:(问题标记为不清楚) 1.我的应用程序是web api(微服务) 2.我使用.Result(阻塞)来避免异步/等待(显然这是错误的!) 我们将有"秒杀"载重量为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;
}
答案 0 :(得分:1)
首先,编写代码的方式根本没有用,因为您通过调用Result
来阻止所有时间。如果这是一件好事,为什么所有的API都不会在内部为你做这件事?!你不能用异步作弊......
如果超过线程范围100的线程池的功能,您将只看到吞吐量增加。
所需的平均线程数为requestsPerSecond * requestDurationInSeconds
。插入一些数字,看看这对你来说是否真实。
我会将关于是同步还是异步的标准帖子链接到您,因为我觉得您不能完全清楚异步IO何时合适。
https://stackoverflow.com/a/25087273/122718为什么EF 6教程使用异步调用? https://stackoverflow.com/a/12796711/122718我们应该切换到默认使用异步I / O吗?
通常,当等待时间很长并且有许多并行请求在运行时,这是合适的。
我的申请没有任何繁忙的工作&#34;在等待回复时要做的事
其他请求进来是如此忙碌的工作。
请注意,当线程被阻塞时,CPU也不会被阻止。另一个线程可以运行。
答案 1 :(得分:1)
你不能在这里实际使用await Task.WhenAll
,因为当您购买下一个异步操作时,依赖于前一个的结果。因此,需要让它们以序列化方式执行。但是,仍然强烈建议您将async / await
用于此类I / O,即;网络服务电话。
代码是在消耗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;
}
答案 2 :(得分:0)
当您进行异步/等待时,您应该全天异步。 阅读Async/Await - Best Practices in Asynchronous Programming
你需要让它们返回异步
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);
编辑:误读OP。不要使用等待Task.WhenAll进行同步调用