2015-08-20 13 views
24

In termini di prestazioni, questi 2 metodi eseguiranno GetAllWidgets() e GetAllFoos() in parallelo?più attende vs Task.WaitAll - equivalente?

C'è qualche motivo per usare l'uno sull'altro? Sembra che ci sia molto successo dietro le quinte con il compilatore, quindi non lo trovo chiaro.

============= MethodA: L'utilizzo di più attende ======================

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

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

    return Ok(customer); 
} 

=============== MethodB: Usando 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

Nel primo esempio i due metodi verranno chiamati in sequenza e nel secondo verranno eseguiti in parallelo, quindi non sono equivalenti. Inoltre, nel tuo secondo metodo stai bloccando mentre esegui le attività. –

+0

MethodA eseguirà '_fooService.GetAllFoos()' solo quando '_widgetService.GetAllWidgets()' ha finito, methodB lo eseguirà quando l'attività incompleta da '_fooService.GetAllFoos()' ritorna. –

risposta

37

La prima opzione non eseguirà contemporaneamente le due operazioni. Eseguirà il primo e attenderà il suo complemento, e solo allora il secondo.

La seconda opzione verrà eseguita contemporaneamente ma le aspetterà in modo sincrono (ad esempio bloccando un thread).

Non è necessario utilizzare entrambe le opzioni poiché il primo si conclude più lentamente del secondo e il secondo blocca una thread senza necessità.

È necessario attendere per entrambe le operazioni in modo asincrono con 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); 
} 

Nota che dopo Task.WhenAll completato entrambi i compiti già completati così in attesa di loro completa immediatamente.

+1

Grazie. Questo è quello di cui avevo bisogno. Il ".Result" mi dava fastidio e la tua risposta lo evitava. – vidalsasoon

+0

@vidalsasoon sicuro .. in qualsiasi momento. – i3arnon

+2

Puoi anche saltare completamente 'Attendi Task.WhenAll (getAllWidgetsTask, getAllFoosTask);' e attendi semplicemente i task (avvia solo il secondo task prima di attendere prima). – kwesolowski

0

Solo la seconda opzione li eseguirà in parallelo . Il tuo primo attenderà ogni chiamata in sequenza.

0

Non appena si richiama il metodo asincrono, verrà avviato. Non è possibile determinare se eseguirà il thread corrente (e quindi eseguirà in modo sincrono) o eseguirà async.

Così, nel primo esempio, il primo metodo inizierà a funzionare, ma in seguito si arresta artificialmente il flusso del codice con l'attesa. E quindi il secondo metodo non sarà invocato prima che il primo venga eseguito.

Il secondo esempio richiama entrambi i metodi senza arrestare il flusso con un'attesa. Pertanto, potrebbero essere eseguiti in parallelo se i metodi sono asincroni.

6

Risposta breve: No.

Task.WaitAll blocca, await restituisce il compito non appena viene rilevato e registra la parte restante della funzione e la continuazione.

Il metodo di attesa "alla rinfusa" che stavi cercando è Task.WhenAll che crea effettivamente un nuovo Task che termina quando tutte le attività che sono state consegnate alla funzione sono state completate.

Come così: await Task.WhenAll({getAllWidgetsTask, getAllFoosTask});

Questo è per la materia di blocco.

Anche la prima funzione non esegue entrambe le funzioni in parallelo.Per ottenere questo lavoro con await dovreste scrivere qualcosa del genere:

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

questo renderà il primo esempio di agire molto simile al metodo Task.WhenAll.

Problemi correlati