【问题标题】:Task.Run() in async method causes thread pool starvation?异步方法中的 Task.Run() 导致线程池饥饿?
【发布时间】:2020-08-05 16:10:04
【问题描述】:

我的 .netcore 应用程序中有这段代码

[HttpPost]
[Route("doSomething")]
public async Task<IActionResult> DoSomethingAsync([FromBody] Input input)
{
    // Do Something
    var task1 = Task.Run(async () => 
    {
        await taskFactory.DoTask(input);
    });

    // Do Something Differently
    var task2 = Task.Run(async () => 
    {
        await taskFactory.DoAnotherTask(input);
    });

    await Task.WhenAll(task1, task2);

    return Accepted();
}

DoTask()DoAnotherTask() 都是相互独立的,可以并行执行,但必须等待它们都处于完成状态。

所以,我创建了两个任务并使用Task.WhenAll() 等待它们。

但是我有一条评论说不要在async 方法中使用Task.Run(),因为它会导致线程池饥饿。

问题 1:我的代码如何导致线程池饥饿?
问题2:如果导致线程池饥饿,如何并行运行两个任务?

【问题讨论】:

  • 你为什么在这里做Task.Run而不是仅仅从DoTask返回任务?
  • 另外,您如何诊断出线程池饥饿是您的问题?
  • 请注意您如何不使用await 来自Task.Run 的结果,而是捕获要在Task.WhenAll 中使用的任务,您也可以对来自DoTask 的结果执行相同操作,并且DoAnotherTask 代替。
  • @DavidG 是的,这是可以避免的。这是不必要的。但只是想了解它是如何导致线程池饥饿的。
  • 将这些调用封装在 Task.Run 中的唯一原因是,如果它们在执行任何 async 代码之前预先具有 CPU 绑定代码。

标签: c# .net-core async-await


【解决方案1】:

对于您的线程池饥饿问题,如果您运行一个已经是异步的任务,则使用 task.run 执行 2 个新任务,并在其中运行 2 个异步方法,每次调用 5 个任务,然后等待完成两者中的一个,每个请求有 6 个任务。

我通常会这样做,你仍然有 4 个任务,但最终池会持续更长时间。

[HttpPost]
[Route("doSomething")]
public async Task<IActionResult> DoSomethingAsync([FromBody] Input input)
{
    // Do Something
    var t1 = taskFactory.DoTask(input);

    // Do Something Differently
    var t2 = taskFactory.DoAnotherTask(input);


    await Task.WhenAll(t1, t2);

    return Accepted();
}

【讨论】:

  • 这可能是一种更好的方法,但没有像他的代码审查员告诉他们的那样回答关于线程池饥饿是否存在风险的 OP 问题。
【解决方案2】:

要自信地回答您的问题,我们必须了解DoTaskDoAnotherTask 方法的实现。在不知道的情况下,我们可以假设它们已正确实现并遵循异步方法的礼仪,即立即返回Task,而不会阻塞调用线程。在这种假设下,答案是:不,您的代码不会导致线程池饥饿。这是因为Task.Run 使用的ThreadPool 线程要做的工作量可以忽略不计,这只是创建一个Task 对象,因此它几乎会立即返回到ThreadPool

应该指出,尽管用Task.Run 包装表现良好的异步委托对ThreadPool 的健康影响微乎其微,但它也没有任何好处。看看这个半相关的问题:Is Task.Run considered bad practice in an ASP .NET MVC Web Application?

【讨论】:

    猜你喜欢
    • 2012-07-26
    • 2016-06-23
    • 2021-02-20
    • 2022-12-18
    • 1970-01-01
    • 2021-06-08
    • 2023-01-07
    • 2015-03-14
    • 1970-01-01
    相关资源
    最近更新 更多