ASP.NET核心,矫枉过正Task.Run()?

ASP.NET Core, overkilling Task.Run()?

假设我们有一个 ASP.NET 核心接收字符串作为有效载荷,大小为几兆字节。第一种方法实现:

[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));
    .....
}

请不要介意现在的return,函数中还有一些事情要做。

那么问题来了,第二种方法是否矫枉过正?如果是这样,区分什么可能是 运行 阻塞以及什么必须移动到另一个线程的边界是什么?

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

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

您通常应该只使用 Task.Run 来卸载(主要是同步的)可以从 运行ning 在其自己的线程上受益的工作。或者在某些情况下,您的工作会花费更长的时间但会阻止当前执行。

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


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

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