C# 我们需要使所有方法都异步吗
我实现了一个Api,它有一个控制器,控制器有一个如下所示的调用树C# 我们需要使所有方法都异步吗,c#,async-await,task-parallel-library,C#,Async Await,Task Parallel Library,我实现了一个Api,它有一个控制器,控制器有一个如下所示的调用树 public async Task<Collection<United.Service.Presentation.LoyaltyModel.Program>> GetRewardPrograms(string languageCode) { return await _referenceDataDomain.GetRewardPrograms(lang
public async Task<Collection<United.Service.Presentation.LoyaltyModel.Program>> GetRewardPrograms(string languageCode)
{
return await _referenceDataDomain.GetRewardPrograms(languageCode).ConfigureAwait(false);
}
公共异步任务GetRewardPrograms(字符串语言代码)
{
返回wait\u referenceDataDomain.GetRewardPrograms(languageCode).ConfigureWait(false);
}
公共异步任务GetRewardPrograms(字符串语言代码)
{
返回wait\u referenceDataProvider.GetRewardPrograms(languageCode).ConfigureWait(false);
}
公共异步任务GetRewardPrograms(字符串语言代码)
{
if(string.IsNullOrEmpty(languageCode))
{
languageCode=\u常量。语言\u代码\u EN\u US;
}
var rewardProgramsSet=新集合();
var format=CacheKeyDictionary.CacheKeyFormat(CacheKeyDictionary.RewardPrograms);
var cacheKey=string.Format(格式,语言代码);
var cacheValue=await\u cacheUtility.getcacheitemsync(cacheKey).ConfigureAwait(false);
if(cacheValue!=null&&cacheValue.Any())
返回缓存值;
if(_commonConfig.useloyltyservice())
{
尝试
{
var cslHttpClient=_serviceProvider.GetRequiredService();
var queryStringParams=new NameValueCollection(){{{“languageCode”,languageCode};
var result=await cslHttpClient.GetAsync(\u commonConfig.LoyaltyServiceUrl(),
“ReferenceDataRewardProgram/idType/a”,queryStringParams,_commonConfig.TimeOutDefault());
if(result!=null&&result.ResponseData!=null&&result.ResponseData.referenceDataRewardProgramList.Count>0)
{
foreach(result.ResponseData.referenceDataRewardProgramList中的变量项)
{
var程序=新程序
{
ProgramID=item.ProgramID.ToInt32(),
代码=item.ProgramCode,
描述=项目。描述,
语言=新语言{LanguageCode=LanguageCode}
};
奖励计划set.Add(计划);
}
}
}
捕获{}
}
if(rewardProgramsSet!=null&&rewardProgramsSet.Any())
{
wait _cacheUtility.SetCacheItemAsync(cacheKey,rewardProgramsSet).ConfigureWait(false);
}
返回奖励程序集;
}
我得到一个代码评审反馈,由于我使所有方法都异步,并且第二个代码块没有执行任何异步操作,我应该返回任务,而不是使用异步方法,因为添加异步将在内部使我的方法进入状态机,这将产生一些性能问题,评审员在本文中引用了我
,如果上述方法存在缺陷,请有人指导我。我通过Stephan发布的这篇文章得到了答案,感谢Jonathan提供链接 以上链接中的以下段落是对我问题的回答: 建议指引 我建议遵循这些准则: 默认情况下不要删除。使用async和Wait来获得自然、易于阅读的代码。 当该方法仅仅是通过或过载时,请考虑ELIDEN。< /P>
// Simple passthrough to next layer: elide.
Task<string> PassthroughAsync(int x) => _service.PassthroughAsync(x);
// Simple overloads for a method: elide.
async Task<string> OverloadsAsync(CancellationToken cancellationToken)
{
... // Core implementation, using await.
}
Task<string> OverloadsAsync() => OverloadsAsync(CancellationToken.None);
// Non-trivial passthrough: use keywords.
async Task<string> PassthroughAsync(int x)
{
// Reasoning: GetFirstArgument can throw.
// Even if it doesn't throw today, some yahoo can change it tomorrow, and it's not possible for them to know to change *this* method, too.
return await _service.PassthroughAsync(GetFirstArgument(), x);
}
// Non-trivial overloads for a method: use keywords.
async Task<string> OverloadsAsync()
{
// Same reasoning as above; GetDefaultCancellationTokenForThisScope can throw.
return await OverloadsAsync(GetDefaultCancellationTokenForThisScope());
}
//到下一层的简单传递:elide。
任务PassthroughAsync(intx)=>\u service.PassthroughAsync(x);
//方法的简单重载:elide。
异步任务重载SASync(CancellationToken CancellationToken)
{
…//核心实现,使用wait。
}
Task OverloadsAsync()=>OverloadsAsync(CancellationToken.None);
//非平凡传递:使用关键字。
异步任务PassthroughAsync(int x)
{
//推理:GetFirstArgument可以抛出。
//即使它今天不抛出,一些雅虎明天可以改变它,他们也不可能知道要改变这个方法。
return wait_service.PassthroughAsync(GetFirstArgument(),x);
}
//方法的非平凡重载:使用关键字。
异步任务重载sasync()
{
//与上面的推理相同;GetDefaultCancellationTokenForThisScope可以抛出。
return wait OverloadsAsync(getdefaultcancellationtokenforthiscope());
}
@Dave感谢您的回复,更新了第二个块,它有异步限定符,在这种特殊情况下,它不做任何事情,只是返回结果,但在其他情况下,我们实现了业务逻辑,并且我们的所有方法都通过域对象使用refdataprovider,因此为了一致性,我们进行了此调用,这称为任务转发,它保存了一个IAsyncStateMachine
实现,并为您提供了一个小的效率,但需要注意的是,该方法不能抛出自己,否则您需要捕获异常并将其放在任务上,以遵守异步和等待模式的语义。我相信有一个斯蒂芬·克利里(Stephen Cleary)的博客涉及到这个话题。评论只是说,在第二个示例中,您可以安全地删除async
和wait
关键字来转发任务,正如Michael所说,在这些场景中删除async可能会对性能产生很小的影响(但它很小,因此您需要经常调用它或在性能敏感的上下文中注意)-我曾经读过这样一篇文章,在每一个级别上展开都会对异常处理和堆栈跟踪产生一些影响,但我记不起来了,这很可能和Michael说的是同一件事。这是一篇非常好的文章:@saurabhvats链接到一篇文章并不是一个真正的答案。请随意添加您自己的:)总结文章中哪些内容真正解决了您的公关问题通常是最佳做法
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;
}
// Simple passthrough to next layer: elide.
Task<string> PassthroughAsync(int x) => _service.PassthroughAsync(x);
// Simple overloads for a method: elide.
async Task<string> OverloadsAsync(CancellationToken cancellationToken)
{
... // Core implementation, using await.
}
Task<string> OverloadsAsync() => OverloadsAsync(CancellationToken.None);
// Non-trivial passthrough: use keywords.
async Task<string> PassthroughAsync(int x)
{
// Reasoning: GetFirstArgument can throw.
// Even if it doesn't throw today, some yahoo can change it tomorrow, and it's not possible for them to know to change *this* method, too.
return await _service.PassthroughAsync(GetFirstArgument(), x);
}
// Non-trivial overloads for a method: use keywords.
async Task<string> OverloadsAsync()
{
// Same reasoning as above; GetDefaultCancellationTokenForThisScope can throw.
return await OverloadsAsync(GetDefaultCancellationTokenForThisScope());
}