.net(dotnet)核心webAPI和异步方法 - 需要反馈



我正在为POC构建我的dotnet core webapi服务,我担心为前进的其他拱门/开发人员设置适当的指导。

"相同"方法签名的变化很少

  1. public dynamic get(字符串name = _defaultName(
  2. public iRinctionResult get(字符串name = _defaultName(
  3. public async任务get(字符串name = _defaultName(

独自一人讨论为什么我要使用动态而不是自定义类型,我试图了解差异和收益。

请更正我的(MIS(理解:

  1. 无法控制HTTP响应,标题,代码等 - 在成功或失败的情况下,全部由框架设置,运行时工具可见返回类型
  2. 更好地控制HTTP响应,但是在执行该方法时它将绑定威胁,没有输出数据类型的定义
  3. 更好地控制HTTP响应,在执行该方法时不会绑定威胁,但会旋转另一个线程来计算结果,并且没有针对输出类型的定义

第三选项的实现将如下:

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方法和产生的有点奇怪的代码。

  1. 无法控制HTTP响应,标题,代码等 - 在成功或失败的情况下,全部由框架设置,运行时工具可见返回类型

您不必使用动态,如果您需要从操作中返回任意响应,则可以使用

public IActionResult Get(string name = _defaultName)
{
    // or any other method which accepts a response object)
    return Ok(someModel);
}
  1. 更好地控制HTTP响应,但是在执行该方法时它将绑定线程,没有输出数据类型的定义

在操作的过程中,请求线程将保持在遵守。但是,如果您不使用任何异步操作(DB访问,网络连接到另一个网站/WebService或将文件读取到数据库(,则可以使用它。

// 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>

  1. 更好地控制http响应,在执行该方法时不会绑定线程,但会旋转另一个线程以计算结果,并且没有针对输出类型的定义

这个假设是错误的。单独使用真正的ASYNC操作(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上的ASP.NET文章中,异步/等待。它是关于ASP.NET MVC 5(旧的WebStack,而不是重写ASP.NET Core(,但该原理仍然适用于ASP.NET Core。

如果您拥有 CPU绑定操作(计算一些复杂的数学等(,则请勿启动新的线程。这将使ASP.NET Core如何管理线程池的方式混乱,您将一无所获,但仍将拥有上下文开关的开销,因此它将降低您的性能而不是提高其性能。

对于CPU绑定的操作,只需runt hem 同步在请求线程上。

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秒的请求每秒

最新更新