Task.Run () в методе asyn c вызывает голодание пула потоков? - PullRequest
2 голосов
/ 22 апреля 2020

У меня есть этот кусок кода в моем приложении .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().

Но у меня есть комментарий к обзору, чтобы не использовать Task.Run() в async метод, поскольку это может привести к истощению пула потоков.

Вопрос 1: Как мой код ведет к истощению пула потоков?
Вопрос 2: Если он приводит к истощению пула потоков, как я могу запустить обе задачи параллельно?

Ответы [ 2 ]

2 голосов
/ 22 апреля 2020

Для вашего вопроса о голодании пула потоков, если вы запускаете задачу, которая уже asyn c, выполняет 2 новые задачи, с помощью task.run, и внутри вы запускаете 2 асин c метода, которые у вас есть на вызов 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();
}

1 голос
/ 22 апреля 2020

Чтобы ответить на ваш вопрос с уверенностью, мы должны знать реализацию методов DoTask и DoAnotherTask. Не зная об этом, мы могли бы просто предположить, что они реализованы правильно и следовать этикету для асин c методов, то есть немедленно возвращать Task, не блокируя вызывающий поток. При таком предположении ответ таков: Нет, ваш код не приводит к истощению пула потоков. Это связано с тем, что поток ThreadPool используется Task.Run* У 1011 * есть незначительный объем работы, который заключается в создании Task объекта, поэтому он будет возвращен обратно к ThreadPool почти сразу.

Следует отметить, что, хотя перенос Правильное поведение асин c делегатов с Task.Run оказывает незначительное влияние на здоровье ThreadPool, но также не приносит никакой пользы. Взгляните на этот полусвязанный вопрос: Считается ли Task.Run плохой практикой в ​​ASP. NET MVC веб-приложении?

...