Async await Behavior [duplicato]
Stavo sperimentando async-wait e mi sono imbattuto in questo comportamento piuttosto strano, almeno per me.
Ho creato tre metodi che simulavano attività a lunga esecuzione.
Considera i due gestori di clic del pulsante:
per button1_click il tempo trascorso è stato di circa 6000 ms mentre button2_click è di circa 3000 ms.
Non riesco a capire perché è successo, cioè 6000 ms contro 3000 ms.
private async Task<string> TaskOne()
{
await Task.Delay(1000);
return "task one";
}
private async Task<string> TaskTwo()
{
await Task.Delay(2000);
return "task two";
}
private async Task<string> TaskThree()
{
await Task.Delay(3000);
return "task three";
}
//time elapsed = 6000+ms
private async void button1_Click(object sender, EventArgs e)
{
var watch = new Stopwatch();
watch.Start();
await TaskOne();
await TaskTwo();
await TaskThree();
watch.Stop();
textBox3.Text = watch.ElapsedMilliseconds.ToString();
}
//time elapsed = 3000+ms
private async void button2_Click(object sender, EventArgs e)
{
var watch = new Stopwatch();
watch.Start();
var taskOne = TaskOne();
var taskTwo = TaskTwo();
var taskThree = TaskThree();
await taskOne;
await taskTwo;
await taskThree;
watch.Stop();
textBox3.Text = watch.ElapsedMilliseconds.ToString();
}
Risposte
In questo caso:
await TaskOne();
await TaskTwo();
await TaskThree();
TaskTwo () non può essere avviato fino al completamento di TaskOne () perché lo stai aspettando. Allo stesso modo TaskThree () non può essere avviato fino a quando TaskTwo () non viene completato a causa dell'attesa.
Nel prossimo:
var taskOne = TaskOne();
var taskTwo = TaskTwo();
var taskThree = TaskThree();
await taskOne;
await taskTwo;
await taskThree;
Stai iniziando tutte e 3 le attività allo stesso tempo e poi le aspetti. Ecco perché ci vuole solo il tempo necessario per eseguire l'attività più lunga. Saresti sorpreso di quante persone non capiscono questo aspetto asincrono. Se le attività non dipendono l'una dall'altra, questa è la strada da percorrere.
Sommario
Il punto da portare a casa qui (ed è un malinteso molto comune altrimenti), è che awaitin realtà significa "attendere" .
operatore di attesa (riferimenti per C #)
Enfasi mia
L'operatore di attesa sospende la valutazione del metodo asincrono che lo racchiude fino al completamento dell'operazione asincrona rappresentata dal suo operando . Al termine dell'operazione asincrona, l'operatore di attesa restituisce il risultato dell'operazione, se presente.
Quando l'operatore di attesa viene applicato all'operando che rappresenta un'operazione già completata, restituisce immediatamente il risultato dell'operazione senza sospensione del metodo di inclusione .
L'operatore di attesa non blocca il thread che valuta il metodo asincrono. Quando l'operatore await sospende il metodo asincrono che lo racchiude, il controllo torna al chiamante del metodo.
Quindi ecco cosa sta succedendo. Nel tuo primo esempio stai iniziando ogni attività e aspettando che vengano completate consecutivamente. Vale a dire, è come chiedere a qualcuno di andare a fare qualcosa e finire, prima di chiedere alla persona successiva di fare qualcosa, ecc
await TaskOne(); // start, do something and wait for it
await TaskTwo(); // start, do something and wait for it
await TaskThree(); // start, do something and wait for it
Il tuo secondo esempio. Stai essenzialmente avviando le 3 attività (calde) e quindi attendi che finiscano una alla volta. Vale a dire che vengono eseguiti contemporaneamente e attesi in sequenza.
Cioè stai dicendo a 3 amici, vai a fare le cose, poi aspetti che torni il primo, poi il secondo e poi il terzo. È molto più efficiente ... Nessun amico fastidioso in giro finché non torna il precedente.
Anche se la seconda attività viene completata prima della prima , in effetti stai ancora aspettando la prima attività prima di esaminare lo stato completato della seconda attività ecc.
var taskOne = TaskOne(); // start, do something
var taskTwo = TaskTwo(); // start, do something
var taskThree = TaskThree(); // start, do something
// all 3 tasks are started
await taskOne; // wait for it
await taskTwo; // wait for it
await taskThree; // wait for it
O allo stesso modo potresti usare Task.WhenAll
Crea un'attività che verrà completata quando tutte le attività fornite saranno state completate.
var taskOne = TaskOne(); // start, do something
var taskTwo = TaskTwo(); // start, do something
var taskThree = TaskThree(); // start, do something
// wait for them all to finish!
await Task.WhenAll(taskOne, taskTwo, taskThree);