2015-08-20 2 views
24

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

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

============= Methoda: Использование нескольких ЖДЕТ ======================

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

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

    return Ok(customer); 
} 

=============== MethodB: Использование 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); 
} 

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

+0

В первом примере два метода будут вызываться последовательно, а во втором они будут выполняться параллельно, поэтому они не эквивалентны. Кроме того, во втором методе вы блокируете выполнение задач. –

+0

MethodA выполнит '_fooService.GetAllFoos()' только тогда, когда '_widgetService.GetAllWidgets()' закончен, методB выполнит его, когда возвращается незавершенная задача из '_fooService.GetAllFoos()'. –

ответ

37

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

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

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

Вы должны ждать, пока обе операции асинхронно с 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 обе задачи уже завершена, так ожидает их завершения немедленно.

+1

Спасибо. Это то, что мне нужно. «.Result» беспокоило меня, и ваш ответ избегает этого. – vidalsasoon

+0

@vidalsasoon конечно .. в любое время. – i3arnon

+2

Вы также можете полностью пропустить 'await Task.WhenAll (getAllWidgetsTask, getAllFoosTask);' и просто ждать задач (просто запустите вторую задачу перед первым). – kwesolowski

0

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

0

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

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

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

6

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

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.

Смежные вопросы