asincrono + attende == sincronizzare?


24

Mi sono imbattuto in questo post che parla di fare richieste web asincrone.

Ora a parte la semplicità, se nel mondo reale, tutto ciò che fai è fare una richiesta asincrona e aspettarla nella riga successiva, non è lo stesso che fare una chiamata di sincronizzazione in primo luogo?


5
Non esattamente. Il codice è sincrono, nel senso che non accade nulla finché non si ottiene un risultato. Tuttavia, sotto, probabilmente hai rinunciato al thread su cui stavi eseguendo fino a quando non è stato restituito il metodo asincrono, quindi ti è stato assegnato un altro thread per continuare l'esecuzione.
R0MANARMY

2
lo è ma con asincrono puoi fare un altro asincrono contemporaneamente e poi attendere il 2, con la sincronizzazione questo non è possibile
maniaco del cricchetto

Ecco un articolo ( tomasp.net/blog/async-compilation-internals.aspx ) che discute alcuni degli aspetti nascosti dell'asincrono in C # - fa parte di una serie che copre la programmazione asincrona in C # e F #.
Paolo

@ratchetfreak: Sì, è ovvio se si effettuano più chiamate.
Sig.

@ R0MANARMY: se la tua app sta facendo altre cose, allora sì e asincrono + wait lo abilita. Akim lo dice meglio! Ma immagina che il codice non sia presente nel gestore button_click o in qualsiasi altro gestore di eventi del genere. Se qualcuno copia il codice alla cieca (asincrono + attendi le righe), in qualsiasi metodo, può portare a una falsa impressione che il codice sia asincrono, ma in effetti potrebbe non esserlo.
Sig.

Risposte:


32

No, a async + await != synccausa della continuazione

Da MSDN "Programmazione asincrona con Async e Await (C # e Visual Basic)"

I metodi asincroni sono intesi come operazioni non bloccanti. Un'espressione waitit in un metodo asincrono non blocca il thread corrente mentre il task atteso è in esecuzione. Al contrario, l'espressione registra il resto del metodo come continuazione e restituisce il controllo al chiamante del metodo asincrono .

Ad esempio, l'esecuzione asincrona non bloccherà il thread dell'interfaccia utente e Some TextBox.Textverrà aggiornata al termine del download

private async void OnButtonClick()
{
   SomeTextBox.Text = await new WebClient().DownloadStringTaskAsync("http://stackoverflow.com/");
}

Molto ben detto!
Sig.

Potresti spiegare in modo più dettagliato. Stai dicendo ... che senza questo ... non saresti in grado di interagire con l'interfaccia utente ... come questo sarebbe sul thread principale. Ciò significa che ciò diventa applicabile solo in un programma di tipo applicativo applicato al Web in cui l'interazione è separata dal thread del server Web. Quindi in un guscio di noce questo diventa importante, cioè non sincronizza * quando il tuo thread principale è il thread in esecuzione. Ciò non creerebbe un comportamento inaspettato, ovvero in un'app (1 thread principale) vengono cliccati due pulsanti .. ma dovresti essere in grado di fare clic su 1 senza il primo completamento?
Seabizkit,

Che dire Console.WriteLine(await GetStringOverNetwork());? E se fosse necessario l'output dell'invocazione asincrona? Il programma bloccherebbe al primo accesso, anche se il thread potrebbe potenzialmente continuare l'esecuzione?
Andrew,

6

No, non è lo stesso.

Il asyncblocco di codice è in attesa che la awaitchiamata torni a continuare, tuttavia il resto dell'applicazione non è in attesa e può comunque continuare normalmente.

Al contrario, una chiamata sincrona farebbe attendere l'intera applicazione o il thread fino al completamento dell'esecuzione del codice per continuare con qualsiasi altra cosa.


la chiamata di sincronizzazione non può essere implementata come async + wait?
maniaco del cricchetto

@ratchetfreak Penso che ci sia un po 'di spese generali per la configurazione di wait / async, quindi non credo che vorresti codificare l'intera applicazione con esso. Lo uso solo per eseguire blocchi di codice potenzialmente di lunga durata in modo che non blocchi le mie applicazioni. :)
Rachel,

5

Per favore, mi permetta di chiarire le cose per quanto riguarda async / wait.

In caso di attesa, la macchina a stati sottostante consente di restituire immediatamente il controllo. Quindi, al termine della chiamata attesa, la macchina a stati sottostante consente di riprendere l'esecuzione sulla linea dopo la chiamata attesa.

Pertanto, il blocco asincrono non viene bloccato né è in attesa del termine della chiamata attesa; Il controllo viene restituito immediatamente quando viene incontrato il comando waitit.

La macchina di stato sottostante è parte della "magia" dietro l'uso di asincrono / attesa che non è in disuso e mancato.


2

Mi sono imbattuto in questo con la stessa domanda in mente, ma dopo aver letto le risposte la domanda sembra persistere, confusa dai riferimenti alla "magia sotto il cofano".

Dalla summenzionata programmazione asincrona :

  • La asyncparola chiave trasforma un metodo in un metodo asincrono, che consente di utilizzare la awaitparola chiave nel suo corpo.
  • Quando awaitviene applicata la parola chiave, sospende il metodo di chiamata e restituisce il controllo al chiamante fino al completamento dell'attività attesa.
  • awaitpuò essere utilizzato solo all'interno di un asyncmetodo.

Il contesto che incontra awaitviene bloccato?

  • . Questa è essenzialmente una barriera di sincronizzazione locale per mantenere uno stato noto nel contesto dell'esecuzione; tranne per il fatto che altri contesti, se presenti, non sono uniti.

Il resto dell'applicazione si blocca su await?

  • Dipende da come è scritta la tua domanda. Se si tratta di una serie di awaitattività ed dipendenti avviate in sequenza nello stesso contesto (vedere: Cercare di capire alcuni comportamenti asincroni / attendi )

    await asyncCall1();
    await asyncCall2();  // waits for asyncCall1() to complete

    in questo modo ognuno awaitbloccherebbe la generazione di quello successivo.

    D'altra parte, gli stessi compiti dipendenti avviati in parallelo verrebbero eseguiti in parallelo e il contesto si bloccherebbe solo al resp. await:

    Task<int> t1 = asyncCall1();
    Task<string> t2 = asyncCall2();  // runs in parallel with asyncCall1()
    int val = await t1;
    string str = await t2;  // waits for asyncCall1() to complete

    In generale, si awaitottiene l'esecuzione nel contesto esterno, da cui viene chiamato il contesto corrente. Tuttavia, se il contesto esterno stesso è in attesa della corrente, allora è come una awaits sequenziale nello stesso contesto.

Quindi, per ottenere i asyncbenefici, è necessario progettare l'applicazione per eseguire diversi contesti paralleli (UI, data-client ecc.), Quindi awaitin un contesto si ottiene l'esecuzione in altri contesti, quindi l'intera applicazione non si bloccherebbe su un individuo await.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.