ASP.NET Core,过度使用Task.Run()?

问题描述 投票:1回答:1

假设我们有一个ASP.NET Core接收字符串作为有效负载,大小顺序为几兆字节。第一种方法实施:

[HttpPost("updateinfos")]
public async Task UpdateInfos()
{
    var len = (int)this.Request.ContentLength;
    byte[] b = new byte[len];
    await this.Request.Body.ReadAsync(b,0,len);
    var content = Encoding.UTF8.GetString(b);
    .....
}

使用ReadAsync读取正文,这很好,因为我们在套接字上有I / O内容并且由于调用本身的性质而使其异步是免费的。但是,如果我们看一下,GetString()方法,纯粹是CPU,阻塞线性复杂性。无论如何,这会以某种方式影响性能,因为其他客户端等待我的字节转换为字符串。我想要避免这种情况,解决方案是在线程池上运行GetString(),通过这个:

[HttpPost("updateinfos")]
public async Task UpdateInfos()
{
    var len = (int)this.Request.ContentLength;
    byte[] b = new byte[len];
    await this.Request.Body.ReadAsync(b,0,len);
    var content = await Task.Run(()=>ASCIIEncoding.UTF8.GetString(b));
    .....
}

请不要介意现在返回,在功能方面还有更多工作要做。

那么问题是,第二种做法是否过度杀伤?如果是这样,区分什么可以作为阻塞运行和必须移动到另一个线程的边界是什么?

asynchronous asp.net-core blocking
1个回答
4
投票

你在那里非常滥用Task.RunTask.Run用于将工作卸载到不同的线程上并异步等待它完成。所以每次Task.Run调用都会导致线程上下文切换。当然,对于不应该在自己的线程上运行的事情来说,这通常是一个非常糟糕的主意。

ASCIIEncoding.UTF8.GetString(b)这样的东西真的很快。创建和管理封装它的线程所涉及的开销比直接在同一线程上执行它要大得多。

您通常应该使用Task.Run来卸载(主要是同步)工作,这些工作可以从在自己的线程上运行中受益。或者,如果您的工作需要更长时间但阻止当前执行。

在您的示例中,情况并非如此,因此您应该同步调用这些方法。


如果你真的想减少该代码的工作,你应该看看如何正常工作流。您在代码中执行的操作是完全读取请求正文流,然后才对其进行处理(尝试转换为字符串)。

您可以直接使用StreamReader将流读取为字符串,而不是分离读取二进制流然后将其转换为字符串的过程。这样,您甚至可以异步地直接读取请求体。因此,取决于您之后对它的实际操作,可能会更有效率。

© www.soinside.com 2019 - 2024. All rights reserved.