我正在为PoC构建我的dotnet核心webapi服务,我担心为其他拱门/开发者提供正确的指导。
"相同"方法签名
单独讨论为什么我使用动态而不是自定义类型,我试图理解差异和好处。
请纠正我的错误理解:
第3个选项的实现如下所示:
public async Task<IActionResult> Get(string name = _defaultName)
{
return await Task.Run(() => {
dynamic response = new System.Dynamic.ExpandoObject();
response.message = $"Hello {name}!";
response.timestamp = DateTime.Now.ToUniversalTime();
if (name.Equals(_defaultName, StringComparison.CurrentCultureIgnoreCase)) {
response.hint = "Add forward slash and your name to the url, e.g.: hostname:port/my name";
}
return Ok(response);
});
}
据我所知,对于HttpClient和EntityFramework等异步依赖,异步方法的实现已经存在。
我想知道如果没有这样的下游异步依赖关系来追求异步webapi方法以及产生一些奇怪的代码是否有意义。
答案 0 :(得分:4)
- 无法控制http响应,标题,代码等 - 在成功或失败的情况下由框架设置,返回类型对运行时工具可见
醇>
你不应该使用动态,如果你需要从动作中返回任意响应,你可以使用
public IActionResult Get(string name = _defaultName)
{
// or any other method which accepts a response object)
return Ok(someModel);
}
- 更好地控制http响应,但它会在执行方法时占用线程,没有输出数据类型的定义
醇>
请求线程将在动作是的持续时间内保持。但是,如果您不使用任何异步操作(数据库访问,与其他网站/ Web服务的网络连接或读/写文件到数据库),使用它就可以了。
// Here no async operations are called, so Task is not necessary
public IActionResult Index(string name = _defaultName)
{
if(!ModelState.IsValid)
{
return BadRequest(ModelState);
}
return Ok();
}
对于异步操作,您应该使用Task<IActionResult>
代替。
- 更好地控制http响应,在执行方法时不会占用线程,但会分离另一个线程来计算结果,并且没有输出类型的定义
醇>
这种假设是错误的。单独使用Task和真正的异步操作(I / O操作,如从文件系统读取,网络连接或访问数据库)将 NOT SPAWN 一个新线程。该操作将启动并且线程返回到线程池。
将启动无新线程。当异步操作完成时,将从线程池中获取一个线程并继续操作。
// No extra thread is called and the request thread is only
// used in between "await" calls
public async Task<IActionResult> Get(string name = _defaultName)
{
var result = await GetResultFromDatabase();
return Ok(someModel);
}
请阅读Stephen Cleary关于MSDN的Async Programming : Introduction to Async/Await on ASP.NET文章。它是关于ASP.NET MVC 5(旧的webstack,而不是重写的ASP.NET Core),但原则仍然适用于ASP.NET Core。
如果您有 CPU绑定操作(计算一些复杂的数学等),那么不会启动新线程。这将搞砸ASP.NET Core如何管理线程池,你将什么也得不到,但仍然会有上下文切换的开销,因此它会降低你的性能而不是增加它。
对于CPU绑定操作,只需在请求线程上同时同步。
public IActionResult Get(string name = _defaultName)
{
// Don't await or run CPU intensive stuff via Task.Run
var result = SomeCpuIntensiveOperation();
return Ok(result);
}
您还可以混合CPU绑定和异步操作
public async Task<IActionResult> Get(string name = _defaultName)
{
// runs async, no extra thread
var valueFromDb = await GetValueFromDb();
// Don't await or run CPU intensive stuff via Task.Run
// runs sync, on request thread
var result = SomeCpuIntensiveOperation(valueFromDb);
return Ok(result);
}
我想知道如果没有这样的下游异步依赖关系来追求异步webapi方法以及产生一些奇怪的代码是否有意义。
根据有关您的第三个假设的新知识,您可以决定
通常,当您有比线程池中的可用线程更多的请求时,异步会更好地扩展。但是大多数小型应用程序从未达到该状态,特别是当它是学习练习或概念证明时。
除非您的流量高的网站每秒处理100或1000次请求,否则您不太可能达到此限制。