【发布时间】:2020-09-03 17:24:31
【问题描述】:
我实现了一个 Api,它有一个控制器,其调用树如下所示。
public async Task<Collection<United.Service.Presentation.LoyaltyModel.Program>> GetRewardPrograms(string languageCode)
{
return await _referenceDataDomain.GetRewardPrograms(languageCode).ConfigureAwait(false);
}
public async Task<Collection<Program>> GetRewardPrograms(string languageCode)
{
return await _referenceDataProvider.GetRewardPrograms(languageCode).ConfigureAwait(false);
}
public async Task<Collection<Program>> GetRewardPrograms(string languageCode)
{
if (string.IsNullOrEmpty(languageCode))
{
languageCode = _constants.LANGUAGE_CODE_EN_US;
}
var rewardProgramsSet = new Collection<Program>();
var format = CacheKeysDictionary.CacheKeyFormat(CacheKeysDictionary.RewardPrograms);
var cacheKey = string.Format(format, languageCode);
var cacheValue = await _cacheUtility.GetCacheItemAsync<Collection<Program>>(cacheKey).ConfigureAwait(false);
if (cacheValue != null && cacheValue.Any())
return cacheValue;
if (_commonConfig.UseLoyaltyService())
{
try
{
var cslHttpClient = _serviceProvider.GetRequiredService<ICSLServiceProxy>();
var queryStringParams = new NameValueCollection() { { "languageCode", languageCode } };
var result = await cslHttpClient.GetAsync<NameValueCollection, RewardProgramsReferenceData>(_commonConfig.LoyaltyServiceUrl(),
"ReferenceDataRewardProgram/idType/a", queryStringParams, _commonConfig.TimeOutDefault());
if (result != null && result.ResponseData != null && result.ResponseData.referenceDataRewardProgramList.Count > 0)
{
foreach (var item in result.ResponseData.referenceDataRewardProgramList)
{
var program = new Program
{
ProgramID = item.ProgramID.ToInt32(),
Code = item.ProgramCode,
Description = item.Description,
Language = new Language { LanguageCode = languageCode }
};
rewardProgramsSet.Add(program);
}
}
}
catch { }
}
if (rewardProgramsSet != null && rewardProgramsSet.Any())
{
await _cacheUtility.SetCacheItemAsync(cacheKey, rewardProgramsSet).ConfigureAwait(false);
}
return rewardProgramsSet;
}
我收到一个代码审查反馈,因为我正在使所有方法异步并且第二个代码块没有执行任何异步操作,所以我应该返回任务而不是使用异步方法,因为添加异步会在内部使我的方法进入状态机,这将造成一些性能问题,审稿人向我推荐了这篇文章 https://medium.com/@deep_blue_day/long-story-short-async-await-best-practices-in-net-1f39d7d84050,如果上述方法有缺陷,请有人指导我。
【问题讨论】:
-
@Dave 感谢您的回复,更新了第二个块,它确实有异步限定符,在这种特殊情况下,它什么都不做,只是返回结果,但在其他情况下,我们确实实现了业务逻辑,我们所有的方法通过域对象使用 refdataprovider,因此为了保持一致性,我们进行此调用
-
这称为任务转发,它节省了
IAsyncStateMachine的实现,并为您提供了一点效率,但需要注意该方法不能自行抛出,否则您需要catch exception 并将其放在任务上以遵守async 和await 模式 的语义。我相信在某个地方有一个涉及这个主题的 Stephen Cleary 博客。评论只是说您可以安全地删除第二个示例中的async和await关键字以转发任务 -
就像迈克尔说的那样,在这些场景中删除异步可能会对性能产生很小的影响(但它很小,所以你需要经常调用它或者在性能敏感的上下文中注意) - 我做到了读过一次,像这样在每个级别展开可能会对异常处理和堆栈跟踪产生一些影响,但我不记得了,这很可能是 Michael 所说的。
-
这是一篇非常值得阅读的文章:blog.stephencleary.com/2016/12/eliding-async-await.html
-
@saurabhvats 文章链接并不是真正的答案。随意添加你自己的:)
标签: c# async-await task-parallel-library