Il presente articolo è stato tradotto automaticamente.

Programmazione asincrona

Introduzione ad Async/Await in ASP.NET

Stephen Cleary

La maggior parte delle risorse online intorno async/attendono presumere che si stanno sviluppando applicazioni client, ma async ha un posto sul server? La risposta è più decisamente "sì." Questo articolo è una panoramica dei concetti di richieste asincrone su ASP.NET, nonché un riferimento per le migliori risorse online. Io non che coprono l'async o attendono la sintassi; Ho già fatto in un post introduttivo (bit.ly/19IkogW) e in un articolo sulle migliori pratiche di async (msdn.microsoft.com/magazine/jj991977). Questo articolo si concentra in particolare sul funzionamento di async su ASP.NET.

Per le applicazioni client, ad esempio Windows Store, Windows desktop e applicazioni per Windows Phone, il principale beneficio di async è la reattività. Questi tipi di applicazioni utilizzano async principalmente per mantenere l'interfaccia utente sensibile. Per le applicazioni server, il principale beneficio di async è la scalabilità. La chiave per la scalabilità di node. js è la sua natura intrinsecamente asincrona; Interfaccia Web aperta per .NET (OWIN) è stato progettato da terra per essere asincrona; e ASP.NET può anche essere asincrona. Async: Non è solo per le applicazioni di interfaccia utente!

Vs sincrono. Gestione richiesta asincrona

Prima di tuffarsi in gestori richieste asincrone, vorrei brevemente esaminare richiesta sincrona come gestori lavorano su ASP.NET. In questo esempio, diciamo che le richieste del sistema dipendono da qualche risorsa esterna, come un database o Web API. Quando arriva una richiesta, ASP.NET prende uno dei suoi thread del pool e assegna a tale richiesta. Perché è scritto in modo sincrono, il gestore richieste chiamerà quella risorsa esterna in modo sincrono. Questo blocca il thread di richiesta fino al ritorno della chiamata alla risorsa esterna. Figura 1 illustra un pool di thread con due thread, uno dei quali è bloccato in attesa di una risorsa esterna.

in attesa in modo sincrono per una risorsa esterna
Figura 1 in attesa in modo sincrono per una risorsa esterna

Alla fine, tale risorsa esterna chiamata restituisce e il thread di richiesta riprende quella richiesta di elaborazione. Quando la richiesta è completa e la risposta è pronta per essere inviato, il thread di richiesta viene restituito al pool di thread.

Questo è bene — fino a quando il server ASP.NET ottiene più richieste di quanto sia il thread per gestire. A questo punto, le richieste extra devono attendere che un thread sia disponibile prima di poter correre. Figura 2 illustra lo stesso server di due thread quando riceve tre richieste.

Server a due thread a ricevere richieste di tre
Figura 2 Server a due thread a ricevere richieste di tre

In questa situazione, le prime due richieste vengono assegnate i thread del pool di thread. Ognuna di queste richieste chiama una risorsa esterna, bloccando le loro discussioni. La terza richiesta deve aspettare per un thread disponibile prima di esso può anche inizio elaborazione, ma la richiesta è già nel sistema. Il timer è in corso, ed è in pericolo di un errore HTTP 503 (servizio non disponibile).

Ma pensaci un attimo: Quella terza richiesta è in attesa per un thread, quando ci sono due altri thread nel sistema efficacemente facendo nulla. Tali discussioni sono appena bloccati in attesa di una chiamata esterna tornare. Non stanno facendo qualsiasi lavoro reale; essi non sono in esecuzione e non hanno alcun tempo di CPU. Tali discussioni sono solo sprecati mentre c'è una richiesta nel bisogno. Questa è la situazione affrontata da richieste asincrone.

Gestori richieste asincrone funzionano in modo diverso. Quando arriva una richiesta, ASP.NET prende uno dei suoi thread del pool e assegna a tale richiesta. Questa volta il gestore richieste chiamerà quella risorsa esterna in modo asincrono. Questo restituisce il thread di richiesta al pool di thread fino a quando la chiamata alla risorsa esterna restituisce. Figura 3 illustra con due thread del pool di thread, mentre la richiesta in modo asincrono è in attesa per la risorsa esterna.

in attesa in modo asincrono per una risorsa esterna
Figura 3 in attesa in modo asincrono per una risorsa esterna

La differenza importante è che il thread di richiesta è stato restituito al pool di thread mentre è in corso la chiamata asincrona. Mentre il thread è nel pool di thread, è non è più associato con quella richiesta. Questa volta, quando termina la chiamata risorsa esterna, ASP.NET prende uno dei suoi thread del pool e vengano riassegnate a quella richiesta. Tale thread continua elaborazione della richiesta. Quando la richiesta viene completata, filo nuovamente restituito al pool di thread. Si noti che con gestori sincroni, nello stesso thread viene utilizzato per la durata della richiesta; con gestori asincroni, al contrario, diversi thread possono essere assegnati alla stessa richiesta (in tempi diversi).

Ora, se dovessero venire tre richieste, il server potrebbe far fronte facilmente. Poiché i thread vengono rilasciati al pool di thread ogni volta che la richiesta ha lavoro asincrono che aspetta, sono liberi di gestire le nuove richieste, così come quelli esistenti. Richieste asincrone consentono un minor numero di thread per gestire un numero maggiore di richieste. Quindi, il vantaggio principale del codice asincrono su ASP.NET è la scalabilità.

Perché non aumentare le dimensioni del Pool di Thread?

A questo punto, una domanda è sempre chiesto: Perché non basta aumentare le dimensioni del pool di thread? La risposta è duplice: Codice asincrono scale sia ulteriormente e più veloce di bloccare il thread del pool.

Codice asincrono può scalare oltre il blocco thread perché utilizza molta meno memoria; ogni thread di pool su un OS moderno ha una pila di 1MB, più uno stack del kernel unpageable. Che non suona come un sacco, fino a quando iniziare a ricevere un sacco di discussioni sul vostro server. Al contrario, la memoria sopra la testa per un'operazione asincrona è molto più piccola. Così, una richiesta con un'operazione asincrona ha molta meno pressione di memoria rispetto a una richiesta con un thread bloccato. Codice asincrono consente di utilizzare più della tua memoria per altre cose (memorizzazione nella cache, ad esempio).

Codice asincrono può scalare più velocemente di blocco thread perché il pool di thread ha un tasso di iniezione limitata. Al momento, il tasso è un thread ogni due secondi. Questo limite di frequenza di iniezione è una buona cosa; evita filo costante costruzione e distruzione. Tuttavia, considerare che cosa succede quando arriva un improvviso diluvio di richieste. Codice sincrono può facilmente impantanarsi come le richieste di utilizzano tutti i thread disponibili e le restanti richieste dovranno aspettare per il pool di thread inserire nuove discussioni. D'altra parte, codice asincrono non ha bisogno di un limite come questo; è "always on," così a parlare. Codice asincrono è più sensibile a sbalzi improvvisi di volume a richiesta.

Tenete a mente che codice asincrono non sostituisce il pool di thread. Questo non è il pool di thread o codice asincrono; si tratta di pool di thread e codice asincrono. Codice asincrono consente all'applicazione di fare un uso ottimale del pool di thread. Esso prende il pool di thread esistenti e gira fino a 11.

Riguardo il Thread facendo il lavoro asincrono?

Ho chiesto questa domanda tutto il tempo. L'implicazione è che ci deve essere qualche thread da qualche parte che sta bloccando la chiamata I/O per la risorsa esterna. Così, codice asincrono libera il thread di richiesta, ma solo a scapito di un altro thread altrove nel sistema, giusto? No, non a tutti.

Per capire perché le richieste asincrone in scala, io sarò traccia un esempio (semplificato) di una chiamata asincrona di I/O. Diciamo che ha bisogno di una richiesta scrivere in un file. Il thread di richiesta chiama il metodo di scrittura asincrona. WriteAsync viene implementata dalla biblioteca BCL (Base Class) e utilizza le porte di completamento per il / o asincrono. Così, la chiamata WriteAsync viene passata al sistema operativo come una scrittura di file asincrono. Il sistema operativo comunica con lo stack di driver, passando i dati da scrivere in un pacchetto di richiesta dei / o (IRP).

Questo è dove le cose si fanno interessanti: Se un driver di dispositivo non può gestire un IRP immediatamente, e ' necessario gestire in modo asincrono. Così, il driver racconta il disco per iniziare a scrivere e restituisce una risposta "in sospeso" per il sistema operativo. Il sistema operativo passa che "in attesa" risposta per la BCL e il BCL restituisce un compito incompleto per il codice di gestione delle richieste. Il codice di gestione delle richieste attende il compito, che restituisce un compito incompleto da tale metodo e così via. Infine, il codice di gestione delle richieste finisce per ritornare un compito incompleto ASP.NET, e il thread di richiesta viene liberato per restituire al pool di thread.

Si consideri ora lo stato corrente del sistema. Ci sono varie strutture I/O che sono state assegnate (ad esempio, le istanze di attività e il GIV), e sono tutti in uno stato in sospeso/incompleto. Tuttavia, non non c'è nessun thread bloccato in attesa che scrivere al completamento dell'operazione. ASP.NET, né della BCL, né l'OS, né il driver ha un thread dedicato al lavoro asincrono.

Quando il disco completa la scrittura dei dati, notifica al suo autista tramite un interrupt. Il driver informa l'OS che ha completato l'IRP, mentre l'OS notifica della BCL tramite la porta di completamento. Un pool di thread risponde a tale notifica completando il compito che è stato restituito da WriteAsync; questo a sua volta riprende il codice di richiesta asincrona. C'erano un paio di discussioni "in prestito" per importi molto brevi di tempo durante questa fase di notifica di completamento, ma nessun thread è stato effettivamente bloccato mentre la scrittura era in corso.

Questo esempio è drasticamente semplificato, ma ottiene attraverso il punto primario: nessun thread è richiesto per il vero lavoro asincrono. Nessun tempo di CPU è necessario spingere effettivamente i byte. C'è anche una lezione secondaria per imparare. Pensare il mondo di driver di dispositivo, come un driver di dispositivo necessario neanche gestire un IRP immediatamente o in modo asincrono. Movimentazione sincrono non è un'opzione. A livello di driver di dispositivo, tutti i/o banale è asincrona. Molti sviluppatori hanno un modello mentale che considera la "API naturale" per operazioni dei / o come sincrono, con l'API asincrono come strato costruito sull'API naturale, sincrono. Tuttavia, che è completamente all'indietro: Infatti, l'API naturale è asincrona; è il sincrone API che vengono implementate utilizzando i/o asincrono!

Perché non c'erano gestori asincroni già?

Se Gestione richiesta asincrona è così meraviglioso, perché non è già disponibile? In realtà, il codice asincrono è così buono per la scalabilità della piattaforma ASP.NET ha sostenuto gestori asincroni e moduli dal albori del Microsoft .NET Framework. Pagine Web asincrone sono state introdotte in ASP.NET 2.0 e MVC ottenuto controller asincrono in ASP.NET MVC 2.

Tuttavia, fino a poco tempo, codice asincrono è sempre stata scomoda per scrivere e difficile da mantenere. Molte aziende hanno deciso che era più facile tutto intorno solo sviluppare il codice in modo sincrono e pagare per server farm più grandi o più costoso di hosting. Ora, hanno trasformato le tabelle: in ASP.NET 4.5, asincrono codice utilizzando async e attendono è quasi facile come scrivere codice sincrono. Come grandi sistemi sposta in cloud hosting e domanda più scala, sempre più aziende sono abbracciare async e attendono su ASP.NET.

Codice asincrono non è un proiettile d'argento

Meravigliosi come gestione richiesta asincrona è, esso non risolverà tutti i vostri problemi. Ci sono alcuni comuni equivoci intorno quali async e attendono può fare su ASP.NET.

Quando alcuni sviluppatori conoscere async e attendono, credono che sia un modo per il codice server per "resa" al client (ad esempio, il browser). Tuttavia, async e attendono su ASP.NET solo "resa" al ASP.NET runtime; il protocollo HTTP rimane invariato, e hai ancora solo una risposta per ogni richiesta. Se hai bisogno SignalR o AJAX o UpdatePanel prima async/attendono, avrai ancora bisogno SignalR o AJAX o UpdatePanel dopo async/attendono.

Asincrona richiesta movimentazione con async e attendono può aiutare la vostra scala di applicazioni. Tuttavia, questo è ridimensionamento su un singolo server; si può ancora bisogno di pianificare scalabilità. Se avete bisogno di un'architettura di scalabilità, che potrai ancora necessità di considerare apolidi, richieste di idempotente e affidabile queueing. Async e attendere un po ' aiutare: Essi consentono di sfruttare al meglio le risorse del server, quindi non avrete scalabilità come spesso. Ma se bisogno di scalabilità, avrete bisogno di una corretta architettura distribuita.

Async e attendono su ASP.NET sono tutti sui / o. Essi veramente eccellere a leggere e scrivere file, record di database e API REST. Tuttavia, non sono buone per le attività associate alla CPU. Può dare il via alcuni lavori di sfondo di attesa task, ma non non c'è alcun punto in questo modo. Infatti, che in realtà farà male la scalabilità interferendo con l'euristica di pool di thread ASP.NET . Se avete associato alla CPU lavoro da fare su ASP.NET, la vostra scommessa migliore è di solo eseguirlo direttamente sul thread di richiesta. Come regola generale, non coda di lavoro al pool di thread su ASP.NET.

Infine, si consideri la scalabilità del sistema nel suo complesso. Un decennio fa, un'architettura comune era di avere un server Web ASP.NET che ha parlato con un SQL Server database back-end. In quel tipo di architettura semplice, di solito il server database è il collo di bottiglia di scalabilità, non il server Web. Rendendo il database chiamate asincrone probabilmente non avrebbe aiutato; si potrebbe certamente usare per scalare il server Web, ma il server di database impedirà il sistema intero di ridimensionamento.

Rick Anderson fa il caso contro le chiamate asincrone database nel suo ottimo blog post, "Mie chiamate di Database dovrebbero essere asincrono?" (bit.ly/1rw66UB). Ci sono due argomenti che supportano questo: primo codice asincrono è difficile (e quindi costoso in tempo sviluppatore rispetto al solo acquisto server più grandi); e in secondo luogo, scalando il server Web rende poco senso se il back-end database è il collo di bottiglia. Entrambi questi argomenti aveva un senso perfetto quando quel post è stato scritto, ma entrambi gli argomenti hanno indebolito nel tempo. Codice asincrono, prima è molto più facile scrivere con async e attendono. In secondo luogo, i dati di back end per siti Web sono scalatura come il mondo si muove al cloud computing. Retro moderna finisce come Microsoft Database SQL Azure, NoSQL e altre API possono scalare molto più di un singolo SQL Server, respingendo il collo di bottiglia al server Web. In questo scenario, async/attendono può portare un enorme beneficio ASP.NETuna scala.

Prima di iniziare

La prima cosa che dovete sapere è che async e attendono sono supportati solo su ASP.NET 4.5. C'è un pacchetto di NuGet chiamato Microsoft.Bcl.Async che permette di async e attendono per .NET Framework 4, ma non la si usa; non funzionerà correttamente! Il motivo è che ASP.NET si doveva cambiare il modo che gestisce la sua gestione richiesta asincrona per lavorare meglio con async e attendono; il pacchetto di NuGet contiene tutti i tipi, il compilatore ha bisogno, ma non sarà patch ASP.NET runtime. Non non c'è nessuna soluzione; è necessario ASP.NET 4.5 o superiore.

Successivamente, essere consapevoli del fatto che ASP.NET 4.5 introduce una modalità di"stranezze" sul server. Se si crea un nuovo progetto ASP.NET 4.5, non devi preoccuparti. Tuttavia, se si aggiorna un progetto esistente a ASP.NET 4.5, stranezze siano tutti accesi. Mi raccomando che si disattivarli tutti modificando Web. config e l'impostazione httpRuntime.targetFramework 4.5. Se l'applicazione non riesce con questa impostazione (e non si vuole prendere il tempo per risolvere il problema), è possibile ottenere almeno async attendono lavoro aggiungendo una chiave appSetting di aspnet:UseTaskFriendlySynchronizationContext con il valore "true". La chiave appSetting è inutile se avete httpRuntime.targetFramework impostata a 4.5. Il team di sviluppo ha un blog post i dettagli di questa nuova "modalità quirks" a bit.ly/1pbmnzK. Suggerimento: Se stai vedendo comportamento strano o eccezioni, e stack di chiamate include LegacyAspNetSynchronizationContext, l'applicazione è in esecuzione in questa modalità quirk. LegacyAspNet­SynchronizationContext non è compatibile con async; è necessario il AspNetSynchronizationContext regolari su ASP.NET 4.5.

In ASP.NET 4.5, tutte le impostazioni di ASP.NET dispongono di valori predefiniti buona per le richieste asincrone, ma ci sono un paio di altre impostazioni che si potrebbe desiderare di cambiare. Il primo è un'impostazione di IIS: considerare l'innalzamento del limite di coda IIS/HTTP.sys (pool di applicazioni | Impostazioni avanzate | Coda lunghezza) dall'impostazione predefinita di 1.000 a 5.000. L'altro è un ambiente di runtime .NET: ServicePointManager, che ha un valore predefinito di 12 volte il numero di core. Il DefaultConnectionLimit limita il numero di connessioni simultanee in uscita per il nome dell'host stesso.

Una parola su richieste di interruzione

Quando ASP.NET elabora una richiesta in modo sincrono, ha un meccanismo molto semplice per l'interruzione di una richiesta (ad esempio, se la richiesta ha superato il timeout): Interromperà il thread di lavoro per tale richiesta. Questo ha un senso nel mondo sincrono, dove ogni richiesta è lo stesso thread di lavoro dall'inizio alla fine. L'interruzione di thread non è meraviglioso per la stabilità a lungo termine dell'oggetto AppDomain, quindi di default ASP.NET riciclerà regolarmente l'applicazione per mantenere le cose pulite.

Con richieste asincrone, ASP.NET non interrompere il thread di lavoro se vuole interrompere una richiesta. Invece, annulla la richiesta utilizzando un CancellationToken. Richiesta asincrona gestori dovrebbero accettare e onorare il token di annullamento. La maggior parte dei quadri più recenti (tra cui Web API, MVC e SignalR) saranno costruire e si passa un CancellationToken direttamente; tutto quello che dovete fare è dichiararla come parametro. È inoltre possibile accedere ASP.NET token direttamente; ad esempio, TimedOutToken è un CancellationToken che annulla quando scade la richiesta.

Come applicazioni sposta nella nube, l'interruzione delle richieste diventa più importante. Applicazioni cloud-based sono più dipendenti servizi esterni che possono prendere una quantità arbitraria di tempo. Ad esempio, un modello standard è per riprovare le richieste esterne con backoff esponenziale; Se l'applicazione dipende da molteplici servizi come questo, è una buona idea applicare un tappo di timeout per la richiesta di elaborazione nel suo complesso.

Stato corrente del supporto Async

Molte biblioteche sono state aggiornate per la compatibilità con async. È stato aggiunto il supporto Async Entity Framework (nel pacchetto EntityFramework NuGet) nella versione 6. Devi essere attenta ad evitare il caricamento lazy quando si lavora in modo asincrono, però, perché il caricamento lazy viene sempre eseguito in modo sincrono. HttpClient (nel pacchetto Microsoft.Net.Http NuGet) è un client HTTP moderno progettato con async in mente, ideale per la chiamata esterna REST API; è un rimontaggio moderno per HttpWebRequest e WebClient. Libreria Client Microsoft Azure Storage (nel pacchetto WindowsAzure.Storage NuGet) aggiunto supporto async in versione 2.1.

Quadri più recenti come Web API e SignalR hanno il pieno supporto per async e attendono. Web API in particolare ha costruito la sua intera pipeline intorno async supporto: non solo i controllori async, ma async filtri e gestori, troppo. Web API e SignalR hanno una storia molto naturale async: si può "just do it" e "appena funziona."

Questo ci porta ad una storia più triste: Oggi, solo parzialmente ASP.NET MVC supporta async e attendono. Il supporto di base c'è — azioni controller async e cancellazione funziona in modo appropriato. Il sito Web ASP.NET ha un assolutamente ottimo tutorial su come utilizzare le azioni del controller async in ASP.NET MVC (bit.ly/1m1LXTx); è la migliore risorsa per iniziare con async su MVC. Purtroppo, non lo fa ASP.NET MVC (attualmente) supporta filtri async (bit.ly/1oAyHLc) o le azioni del bambino async (bit.ly/1px47RG).

ASP.NET Web Form è un framework più anziano, ma anche ha un supporto adeguato per async e attendono. Ancora una volta, la risorsa migliore per iniziare è il tutorial sul sito ASP.NET per async Web Form (bit.ly/Ydho7W). Con Web Form, async supporto è opt-in. Devi prima impostare Page.Async su true, quindi è possibile utilizzare PageAsyncTask registrare async lavoro con quella pagina (in alternativa, è possibile utilizzare i gestori eventi void asincroni). PageAsyncTask supporta anche l'annullamento.

Se si dispone di un gestore HTTP personalizzato o un modulo HTTP, ASP.NET ora supporta versioni asincrone di quelli, pure. I gestori HTTP sono supportati tramite HttpTaskAsyncHandler (bit.ly/1nWpWFj) e i moduli HTTP vengono supportati tramite EventHandlerTaskAsyncHelper (bit.ly/1m1Sn4O).

Al momento, il team ASP.NET sta lavorando su un nuovo progetto conosciuto come vNext ASP.NET . In vNext, pipeline intera è asincrona per impostazione predefinita. Attualmente, il piano è quello di combinare MVC e Web API in un quadro unico che ha il pieno supporto per async attendono (inclusi filtri async e componenti vista async). Altri Framework async pronto come SignalR troveranno una casa naturale in vNext. Il futuro è veramente, async.

Rispettare le reti di sicurezza

ASP.NET 4.5 ha introdotto un paio di nuove "reti di sicurezza" che aiutare a catturare asincrone problemi nell'applicazione. Questi sono su per impostazione predefinita e dovrebbe restare acceso.

Quando un gestore sincrono tenta di eseguire il lavoro asincrono, si otterrà un'eccezione InvalidOperationException con il messaggio, "un'operazione asincrona non può essere avviata in questo momento." Ci sono due cause principali per questa eccezione. Il primo è quando una pagina Web Form ha i gestori di eventi asincroni, ma trascurato per impostare Page.Async su true. Il secondo è quando il codice sincrono chiama un metodo void async. Questo è un altro motivo per evitare async vuoto.

L'altra rete di sicurezza è per gestori asincroni: Quando un gestore asincrono completa la richiesta, ma ASP.NET rileva lavoro asincrono che non ha completato, si ottiene un invalido­OperationException con il messaggio, "un modulo asincrona o gestore completato mentre un'operazione asincrona era ancora in sospeso." Ciò è solitamente dovuto codice asincrono chiamando un metodo void async, ma può anche essere causato da un uso improprio di un componente del modello asincrono basato su eventi (EAP) (bit.ly/19VdUWu).

C'è un'opzione che consente di spegnere entrambe le reti di sicurezza: AllowAsyncDuringSyncStages (può inoltre essere impostato nel file Web. config). Alcune pagine su Internet suggeriscono questa impostazione ogni volta che vedete queste eccezioni. Non posso dissentire con più veemenza. Seriamente, non so perché questo è anche possibile. Disabilitare le reti di sicurezza è un'idea orribile. Il solo possibile motivo che posso pensare è se il codice è già facendo alcuni estremamente avanzata roba asincrona (di là di qualsiasi cosa che ho mai tentato), e tu sei un genio multithreading. Quindi, se avete letto questo intero articolo sbadigliando e pensare, "per favore, non sono n00b," quindi suppongo che si può considerare disabilitando le reti di sicurezza. Per il resto di noi, questa è un'opzione estremamente pericolosa e non deve essere impostata se non sei pienamente consapevole delle ramificazioni.

Guida introduttiva

Finalmente! Pronto per iniziare a prendere vantaggio di async e attendono? Apprezziamo la vostra pazienza.

In primo luogo, consultare la sezione "Asincrono codice è non un Silver Bullet" in questo articolo per garantire async/attendono è favorevole alla vostra architettura. Quindi, aggiornare l'applicazione ASP.NET 4.5 e disattivare la modalità non standard (non è una cattiva idea di correre a questo punto solo per assicurarsi che niente si rompe). A questo punto, sei pronto per iniziare il lavoro vero async/attendono.

Partono le "foglie". Pensare a come le vostre richieste vengono elaborate e identificano qualsiasi operazioni dei / O-basata, soprattutto niente basati sulla rete. Esempi comuni sono le query di database e comandi e chiamate ad altri servizi Web e API. Scegli uno per cominciare e fare un po' di ricerca per trovare la migliore opzione per eseguire tale operazione utilizzando async/attendono. Molti dei tipi incorporati BCL sono ora pronti per async in .NET Framework 4.5; ad esempio, SmtpClient ha i metodi SendMailAsync. Alcuni tipi hanno pronto async sostituzioni disponibili; ad esempio, HttpWebRequest e WebClient possono essere sostituiti con HttpClient. Aggiornare le versioni della libreria, se necessario; ad esempio, Entity Framework ottenuto metodi async-compatibili in EF6.

Tuttavia, per evitare "falsi asincronia" nelle biblioteche. Asincronia falso è quando un componente ha un'API async-pronto, ma è implementata da avvolgimento appena l'API sincrona all'interno di un pool di thread. Che è controproducente per la scalabilità su ASP.NET. Un esempio prominente di asincronia falso è Newtonsoft JSON.NET, una libreria altrimenti eccellente. È meglio non chiamare le versioni asincrone (false) per la serializzazione JSON; Basta chiamare le versioni sincrone. Un esempio più complicato di asincronia falso è i flussi di file BCL. Quando un flusso di file viene aperto, deve essere aperto in modo esplicito per accesso asincrono; in caso contrario, utilizzerà falso asincronia, bloccando in modo sincrono un pool di thread sul file legge e scrive.

Una volta che hai scelto una "foglia", quindi iniziare con un metodo nel codice che chiama il API e farne un metodo asincrono che chiama l'API async-pronti via await. Se stai chiamando l'API supporta CancellationToken, il metodo dovrebbe prendere un CancellationToken e passarlo al metodo API.

Quando si contrassegna un metodo asincrono, è necessario modificare il tipo restituito: void diventa compito, e un tipo non void T diventa compito < T >. Troverete che poi tutti i chiamanti di quel metodo necessario per diventare async così possono attendere il task e così via. Inoltre, aggiungere Async al nome del metodo, per seguire le convenzioni del modello asincrono basato su attività (bit.ly/1uBKGKR).

Consentire il pattern async/attendono a crescere il tuo stack di chiamata verso il "tronco". Presso il tronco, il codice si interfaccia con ASP.NET framework (MVC, Web Form, Web API). Leggi il tutorial appropriato nella sezione "Stato attuale del supporto Async" precedentemente in questo articolo per integrare il codice asincrono con il framework.

Lungo la strada, identificare qualsiasi stato di thread locale. Perché le richieste asincrone possono cambiare thread, lo stato di thread locale quali ThreadStaticAttribute, ThreadLocal < T >, gli slot di dati filo e CallContext.GetData/SetData non funzionerà. Sostituire questi con HttpContext, se possibile; o è possibile memorizzare dati modificabili in CallContext.LogicalGetData/LogicalSetData.

Ecco un suggerimento che ho trovato utile: è possibile duplicare (temporaneamente) il codice per creare una partizione verticale. Con questa tecnica, non cambiano i metodi sincroni al asincrona; Potete copiare l'intero metodo sincrono e quindi modificare la copia per essere asincrona. È possibile quindi mantenere la maggior parte dell'applicazione utilizzando i metodi sincroni e creare solo una piccola fetta verticale di asincronia. Questo è grande se si desidera esplorare async come un proof-of-concept o test su solo una parte della domanda per ottenere una sensibilità per quanto potrebbe scalare il sistema di carico. Si può avere una richiesta (o pagina) che è completamente asincrona, mentre il resto dell'applicazione rimane sincrono. Naturalmente, non si desidera mantenere duplicati per ogni uno dei vostri metodi; alla fine, tutto il codice associate ai / O sarà async e le copie sincrone possono essere rimosso.

Conclusioni

Spero che questo articolo ti ha aiutato a ottenere una messa a terra concettuale in richieste asincrone su ASP.NET. Utilizzando async e attendono, è più facile che mai per scrivere applicazioni Web, servizi e API che rendono massime usano delle loro risorse del server. Async è impressionante!


Stephen Cleary è un programmatore che vivono nel nord del Michigan, padre e marito. Ha lavorato con multithreading e asincrona di programmazione per 16 anni e ha utilizzato il supporto async in Microsoft .NET Framework poiché la prima anteprima di tecnologia di comunità. Sua homepage, compreso il suo blog, è a stephencleary.com.

Grazie al seguente Microsoft esperto tecnico per la revisione di questo articolo: James McCaffrey