it-swarm.com.ru

несколько ждет против Task.WaitAll - эквивалент?

С точки зрения производительности, будут ли эти 2 метода работать GetAllWidgets() и GetAllFoos() параллельно?

Есть ли причина использовать один над другим? Похоже, что за кулисами с компилятором происходит много событий, поэтому я не нахожу это понятным.

============= Метод A: Использование нескольких ожиданий ======================

public async Task<IHttpActionResult> MethodA()
{
    var customer = new Customer();

    customer.Widgets = await _widgetService.GetAllWidgets();
    customer.Foos = await _fooService.GetAllFoos();

    return Ok(customer);
}

=============== Метод B: Использование Task.WaitAll =====================

public async Task<IHttpActionResult> MethodB()
{
    var customer = new Customer();

    var getAllWidgetsTask = _widgetService.GetAllWidgets();
    var getAllFoosTask = _fooService.GetAllFos();

    Task.WaitAll(new List[] {getAllWidgetsTask, getAllFoosTask});

    customer.Widgets = getAllWidgetsTask.Result;
    customer.Foos = getAllFoosTask.Result;

    return Ok(customer);
}

=====================================

40
vidalsasoon

Первый вариант не будет выполнять две операции одновременно. Он выполнит первый и дождется его завершения, и только потом второй.

Второй вариант будет выполнять оба одновременно, но будет ожидать их синхронно (т.е. при блокировке потока).

Вы не должны использовать оба варианта, так как первый завершается медленнее, чем второй, а второй блокирует поток без необходимости.

Вы должны ожидать обе операции асинхронно с Task.WhenAll:

public async Task<IHttpActionResult> MethodB()
{
    var customer = new Customer();

    var getAllWidgetsTask = _widgetService.GetAllWidgets();
    var getAllFoosTask = _fooService.GetAllFos();

    await Task.WhenAll(getAllWidgetsTask, getAllFoosTask);

    customer.Widgets = await getAllWidgetsTask;
    customer.Foos = await getAllFoosTask;

    return Ok(customer);
}

Обратите внимание, что после выполнения Task.WhenAll обе задачи уже выполнены, поэтому ожидание их завершается немедленно.

68
i3arnon

Краткий ответ: Нет.

Task.WaitAll блокирует, await возвращает задачу, как только она встретится, и регистрирует оставшуюся часть функции и продолжения.

Методом «массового» ожидания, который вы искали, является Task.WhenAll, который фактически создает новую Task, которая завершается, когда все задачи, переданные функции, выполнены.

Вроде так: await Task.WhenAll({getAllWidgetsTask, getAllFoosTask});

Это для блокирующего вопроса.

Также ваша первая функция не выполняет обе функции параллельно. Чтобы это работало с await, вам нужно написать что-то вроде этого:

var widgetsTask = _widgetService.GetAllWidgets();
var foosTask = _fooService.GetAllWidgets();
customer.Widgets = await widgetsTask;
customer.Foos = await foosTask;

Это сделает первый пример, который будет очень похож на метод Task.WhenAll.

13
Nitram

Только ваш второй вариант будет запускать их параллельно. Ваш первый будет ждать каждого вызова в последовательности.

0
nvoigt

Как только вы вызовете асинхронный метод, он начнет выполняться. Будет ли он выполняться в текущем потоке (и, следовательно, работать синхронно) или будет работать асинхронно, определить невозможно. 

Таким образом, в вашем первом примере первый метод начнет работать, но затем вы искусственно останавливаете поток кода с помощью await. И, таким образом, второй метод не будет вызван, пока не будет выполнен первый.

Второй пример вызывает оба метода без остановки потока с ожиданием. Таким образом, они могут работать параллельно, если методы асинхронные. 

0
Kasper Holdum