async – stai sul thread corrente?

Ho letto l’ articolo di Eric Lippert su async e sulle confusioni che la gente aveva con parole chiave async . Egli ha detto :

it ( async ) significa “questo metodo contiene il stream di controllo che implica l’attesa di operazioni asincrone e verrà quindi riscritto dal compilatore nello stile di passaggio continuo per garantire che le operazioni asincrone possano riprendere questo metodo nel punto giusto.” L’intero punto dei metodi asincroni si rimane sul thread corrente il più ansible

Non lo capisco Se eseguo un metodo asincrono ( Task ) e viene eseguito, sicuramente viene eseguito su un altro thread.

Inoltre, se scrivo un metodo utilizza await , (imho) rilascia il normale stream di controllo, e il codice viene rifatto allo stesso modo ” ContinueWith ” più tardi, su un altro thread.

L’ho provato con (console):

 /*1*/ public void StartChain() /*2*/ { /*3*/ var a = FuncA(); /*4*/ Console.WriteLine(a.Result); /*5*/ } /*6*/ /*7*/ public async Task  FuncA() /*8*/ { /*9*/ Console.WriteLine("A--" + Thread.CurrentThread.ManagedThreadId); /*10*/ var t = await FuncB(); /*11*/ Console.WriteLine("B--" + Thread.CurrentThread.ManagedThreadId); /*12*/ return t; /*13*/ } /*14*/ /*15*/ public async Task  FuncB() /*16*/ { /*17*/ Console.WriteLine("C--" + Thread.CurrentThread.ManagedThreadId); /*18*/ await Task.Delay(2000); /*19*/ Console.WriteLine("D--" + Thread.CurrentThread.ManagedThreadId); /*20*/ return 999; /*21*/ } /*22*/ /*23*/ void Main() /*24*/ { /*25*/ StartChain(); /*26*/ } /*27*/ 

il risultato è:

 A--7 C--7 D--17 <-----D and B are on different thread B--17 999 

Che cosa intendeva dire Eric dicendo “stai al corrente thread”?

modifica 1:

in asp.net restituisce anche ID thread diverso.

 public async Task FuncA() { Response.Write("
C----" + Thread.CurrentThread.ManagedThreadId); var t = await FuncB(); Response.Write("
D----" + Thread.CurrentThread.ManagedThreadId); return t; } public async Task FuncB() { Response.Write("
E----" + Thread.CurrentThread.ManagedThreadId); await Task.Delay(2000); Response.Write("
F----" + Thread.CurrentThread.ManagedThreadId); return 999; } protected async void Page_Load(object sender, EventArgs e) { Response.Write("
A----" + Thread.CurrentThread.ManagedThreadId); var a=await FuncA(); Response.Write("
B----" + Thread.CurrentThread.ManagedThreadId); } A----8 C----8 E----8 F----9 D----9 B----9

modifica 2

(dopo aver ottenuto una risposta)

sembra che il thread sia servito solo alle app GUI:. Eseguo questo codice su winform

  public async Task FuncA() { textBox1.Text +=Environment.NewLine+ "\nC----" + Thread.CurrentThread.ManagedThreadId; var t = await FuncB(); textBox1.Text += Environment.NewLine + "\nD----" + Thread.CurrentThread.ManagedThreadId; return t; } public async Task FuncB() { textBox1.Text += Environment.NewLine + "\nE----" + Thread.CurrentThread.ManagedThreadId; await Task.Delay(2000); textBox1.Text += Environment.NewLine + "\nF----" + Thread.CurrentThread.ManagedThreadId; return 999; } private async void Form1_Load(object sender, EventArgs e) { textBox1.Text += Environment.NewLine + "\nA----" + Thread.CurrentThread.ManagedThreadId; var a = await FuncA(); textBox1.Text += Environment.NewLine + "\nB----" + Thread.CurrentThread.ManagedThreadId; } 

inserisci la descrizione dell'immagine qui

Il supporto async / await è stato aggiunto per aiutare i programmatori a scrivere GUI che non si bloccano. Particolarmente utile nelle app Store e il motivo principale per cui è stato aggiunto a C # v5, WinRT è un’API piuttosto ostile che ha molti metodi asincroni.

Lo scenario “stay on the same thread” è molto importante in un’applicazione GUI, richiesto perché una GUI non è thread-safe. Richiede tuttavia un loop di messaggi, l’unico modo per riprendere il codice asincrono sullo stesso thread. Il ciclo dei messaggi è la soluzione principale al problema produttore-consumatore . Chiaramente il tuo programma non ne ha uno, sembra molto simile a un’app in modalità console. Quindi non ottieni questo comportamento, riprende su un thread di lavoro.

Non è un grosso problema, in realtà non è necessario riprenderlo sullo stesso thread poiché una console è comunque thread-safe. Beh, soprattutto, senza contare il blocco aggiunto in .NET 4.5 quando chiedi l’input. Il che ovviamente significa anche che non hai un heckofalot di utilizzo per async / await, anche una Task funziona bene.

Se eseguo un metodo asincrono e viene eseguito, sicuramente viene eseguito su un altro thread.

No, in genere viene eseguito su un altro thread. Non funziona sicuramente su un altro thread.

Smetti di pensare ai fili per un momento e pensa alla natura dell’asincronia. La natura dell’asincronia è:

  • Ho un stream di lavoro che sto attualmente eseguendo.
  • Non posso procedere in questo stream di lavoro finché non ottengo informazioni X.
  • Farò qualcos’altro finché non avrò informazioni X.
  • Ad un certo punto nel futuro, una volta che avrò X, tornerò da dove ho interrotto il mio stream di lavoro e continuerò.

Supponiamo che stai facendo le tue tasse e nel mezzo di questo complicato stream di lavoro hai una grande aggiunta da eseguire. Puoi eseguire alcune operazioni, quindi ricordare dove ti trovi e andare a pranzo. Quindi torna indietro ed esegui alcune altre operazioni, quindi ricorda dove sei e dai da mangiare al gatto. Quindi torna indietro ed esegui alcune altre operazioni, quindi ricorda dove sei e lava i piatti. Quindi terminare i calcoli e riprendere da dove si era interrotto nel stream di lavoro.

È un calcolo asincrono, ma è necessario un solo operatore per farlo. Avere più lavoratori è solo un modo particolarmente comodo per fare asincronia, non è un requisito.

La terminologia “thread” di Eric Lippert è semplificata. Ho async / await sul mio blog che spiega come l’ await catturerà il contesto attuale e la userà per riprendere il metodo async .

Se ci si trova in un contesto di interfaccia utente, il contesto è il singolo thread dell’interfaccia utente e il metodo async verrà ripristinato su quel thread. Altrimenti, le regole sono un po ‘più complicate. In particolare, le app della console non forniscono alcun contesto, quindi i metodi async per impostazione predefinita riprendono nel pool di thread.