Ho letto da qualche parte su Stackoverflow in un commento la seguente analogia. Perché è in un commento non riesco a trovarlo facilmente, quindi nessun collegamento ad esso.
Supponiamo di dover fare colazione. Fai bollire delle uova e tosta un po 'di pane.
Se si inizia a bollire le uova, poi da qualche parte nel sottoprogramma "far bollire delle uova" si dovrà aspettare fino a quando le uova sono bolliti
sincrono sarebbe di attendere fino a quando le uova sono finiti bollente prima di iniziare subroutine "Pane tostato".
Tuttavia sarebbe più efficiente se mentre le uova vengono bollite, non si aspetta, ma si inizia a tostare le uova. Quindi attendi che uno di loro finisca e continui il processo "Boil Eggs" o "Toast Bread" a seconda di cosa finisce prima. Questo è asincrono ma non simultaneo. È ancora una persona che sta facendo tutto.
Un terzo metodo sarebbe quello di assumere un cuoco che bolle uova mentre si tosta il pane. Questo è davvero concomitante: due persone stanno facendo qualcosa. Se sei davvero ricco, puoi anche noleggiare un tostapane, mentre leggi il giornale, ma ciao, non viviamo tutti in Downton Abbey ;-)
Torna alla tua domanda.
Nr 2: sincrono: il thread principale fa tutto il lavoro. Questo thread ritorna dopo che l'uovo è stato bollito prima che il chiamante possa fare qualcos'altro.
Nr 1 non è dichiarato asincrono. Ciò significa che, sebbene inizi un altro thread che svolgerà il lavoro, il tuo interlocutore non può continuare a fare qualcos'altro, e sebbene tu possa, non lo fai, devi solo aspettare che l'uovo sia bollito.
La terza procedura è dichiarata asincrona. Ciò significa che non appena inizia l'attesa dell'uovo, il chiamante può fare qualcos'altro, come tostare il pane. Nota che questo funziona tutto il lavoro è fatto da un thread.
Se il chiamante aspetterebbe non fare altro che attendere, non sarebbe molto utile, a meno che il chiamante non sia dichiarato asincrono. Ciò darebbe al chiamante del chiamante l'opportunità di fare qualcos'altro.
In genere quando si utilizza async-aspettano correttamente, viene visualizzato il seguente: - Ogni funzione dichiarata asincrone ritorna Task invece di vuoto, e Task < TResult> al posto di TResult - C'è una sola eccezione: il gestore di eventi restituisce vuoto invece di Attività. - Ogni funzione che richiama una funzione asincrona dovrebbe essere dichiarata asincrona, altrimenti usare async-await non è molto utile - Dopo aver chiamato un metodo asincrono è possibile iniziare a tostare il pane mentre l'uovo viene bollito.Quando il pane è tostato, puoi aspettare l'uovo, o puoi controllare se l'uovo è pronto durante la tostatura, o forse il più efficiente sarebbe attendere Task.WhenAny, per continuare a terminare l'uovo o il toast o attendere Task. QuandoTutto quando non hai nulla di utile da fare finchè non entrambi sono finiti.
Spero che questa analogia aiuti
Il primo viene eseguito in modo asincrono, il secondo no e blocca. Il risultato viene restituito in modo sincrono racchiuso in un'attività. Il terzo è quasi lo stesso del primo: "async/await" semplifica semplicemente l'awating, non rende nulla asincrono. Il terzo in realtà ha qualche cruft inutile perché il risultato non è effettivamente utilizzato all'interno della funzione –
PS. Non sto postando questa risposta come risposta perché ci sono un sacco di domande simili –
Nota: questo è "asincrono sulla sincronizzazione": il servizio di back-end ('GetBar') è fondamentalmente un'API sincrona, e lo stai esponendo tramite un shim 'async'. Il * solo * motivo per farlo è per cose come liberare l'interfaccia utente per dipingere. Non raggiunge il set più ampio di obiettivi 'async': hai ancora ** un ** thread sat bloccato sul risultato - semplicemente non è il * thread * originale. –