简体   繁体   English

异步方法中的 Task.Run() 导致线程池饥饿?

[英]Task.Run() in async method causes thread pool starvation?

I have this piece of code in my .netcore application我的 .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() and DoAnotherTask() are both independent of each other and can be executed in parallel but they have to be awaited until both of them are in completed status. DoTask()DoAnotherTask()都是相互独立的,可以并行执行,但必须等待它们都处于完成状态。

So, I created two tasks and awaited them using Task.WhenAll() .因此,我创建了两个任务并使用Task.WhenAll()等待它们。

But I have got a review comment to not use Task.Run() in an async method as it can lead to thread pool starvation.但是我有一个评论评论不要在async方法中使用Task.Run() ,因为它可能导致线程池饥饿。

Question 1: How does my code leading to thread pool starvation?问题 1:我的代码如何导致线程池饥饿?
Question 2: If it is leading to thread pool starvation, how can I run both tasks in parallel?问题2:如果导致线程池饥饿,我该如何并行运行这两个任务?

For your thread pool starvation question, if you run a task, which is already async, executes 2 new Tasks, with task.run and inside that you run 2 async methods you have per call 5 Tasks, then you await the completion of both and you are at 6 Tasks per Request.对于您的线程池饥饿问题,如果您运行一个已经是异步的任务,则使用 task.run 执行 2 个新任务,并且在其中运行 2 个异步方法,每次调用 5 个任务,然后等待两者的完成每个请求有 6 个任务。

I usually do smth like this, you still have 4 Tasks, but in the end the pool would last longer.我通常会这样做,你仍然有 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();
}

To answer your question with confidence we must know the implementation of the DoTask and DoAnotherTask methods.要自信地回答您的问题,我们必须了解DoTaskDoAnotherTask方法的实现。 Without knowing it we could just assume that they are implemented properly and follow the etiquette for async methods, which is to return a Task immediately, without blocking the calling thread.在不知道的情况下,我们可以假设它们已正确实现并遵循异步方法的礼仪,即立即返回Task ,而不会阻塞调用线程。 Under this assumption, the answer is: No, your code doesn't lead to thread pool starvation.在这种假设下,答案是:不,您的代码不会导致线程池饥饿。 This is because the ThreadPool thread employed by Task.Run has a negligible amount of work to do, which is just to create a Task object, so it will be returned back to the ThreadPool almost immediately.这是因为Task.Run使用的ThreadPool线程要做的工作量可以忽略不计,它只是创建一个Task object,所以它几乎会立即返回到ThreadPool

It should be pointed out that although wrapping well behaved async delegates with Task.Run has negligible impact to the health of the ThreadPool , it offers no benefit either.应该指出的是,尽管使用Task.Run包装表现良好的异步委托对ThreadPool的健康影响微乎其微,但它也没有任何好处。 Take a look at this semi-related question: Is Task.Run considered bad practice in an ASP .NET MVC Web Application?看看这个半相关的问题: Task.Run 在 ASP .NET MVC Web Application 中被认为是不好的做法吗?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM