Eseguire operazioni asincrone in ASP.NET MVC utilizzare un thread da ThreadPool su .NET 4


158

Dopo questa domanda, mi sento a mio agio quando utilizzo le operazioni asincrone in ASP.NET MVC. Quindi, ho scritto due post sul blog su questo:

Ho troppi malintesi nella mente riguardo alle operazioni asincrone su ASP.NET MVC.

Sento sempre questa frase: l' applicazione può ridimensionarsi meglio se le operazioni vengono eseguite in modo asincrono

E ho sentito anche questo tipo di frasi: se hai un volume enorme di traffico, potresti essere meglio non eseguire le tue query in modo asincrono - consumare 2 thread extra per soddisfare una richiesta toglie risorse da altre richieste in arrivo.

Penso che queste due frasi siano incoerenti.

Non ho molte informazioni su come funziona threadpool su ASP.NET ma so che threadpool ha una dimensione limitata per i thread. Quindi, la seconda frase deve essere correlata a questo problema.

E vorrei sapere se le operazioni asincrone in ASP.NET MVC utilizzano un thread da ThreadPool su .NET 4?

Ad esempio, quando implementiamo un AsyncController, come viene strutturata l'app? Se ricevo traffico intenso, è una buona idea implementare AsyncController?

C'è qualcuno là fuori che può portare via questa tenda nera davanti ai miei occhi e spiegarmi l'accordo sull'asincronia su ASP.NET MVC 3 (NET 4)?

Modificare:

Ho letto questo documento di seguito quasi centinaia di volte e capisco l'affare principale, ma ho ancora confusione perché ci sono troppi commenti incoerenti.

Utilizzo di un controller asincrono in ASP.NET MVC

Modificare:

Supponiamo che io abbia un'azione del controller come di seguito (non un'implementazione di AsyncControllerperò):

public ViewResult Index() { 

    Task.Factory.StartNew(() => { 
        //Do an advanced looging here which takes a while
    });

    return View();
}

Come vedi qui, lancio un'operazione e me ne dimentico. Quindi, torno immediatamente senza aspettare che sia completato.

In questo caso, questo deve usare un thread da Threadpool? In tal caso, al termine, cosa succede a quel thread? Non GCentra e ripulire subito dopo che completa?

Modificare:

Per la risposta di @ Darin, ecco un esempio di codice asincrono che parla al database:

public class FooController : AsyncController {

    //EF 4.2 DbContext instance
    MyContext _context = new MyContext();

    public void IndexAsync() { 

        AsyncManager.OutstandingOperations.Increment(3);

        Task<IEnumerable<Foo>>.Factory.StartNew(() => { 

           return 
                _context.Foos;
        }).ContinueWith(t => {

            AsyncManager.Parameters["foos"] = t.Result;
            AsyncManager.OutstandingOperations.Decrement();
        });

        Task<IEnumerable<Bars>>.Factory.StartNew(() => { 

           return 
                _context.Bars;
        }).ContinueWith(t => {

            AsyncManager.Parameters["bars"] = t.Result;
            AsyncManager.OutstandingOperations.Decrement();
        });

        Task<IEnumerable<FooBar>>.Factory.StartNew(() => { 

           return 
                _context.FooBars;
        }).ContinueWith(t => {

            AsyncManager.Parameters["foobars"] = t.Result;
            AsyncManager.OutstandingOperations.Decrement();
        });
    }

    public ViewResult IndexCompleted(
        IEnumerable<Foo> foos, 
        IEnumerable<Bar> bars,
        IEnumerable<FooBar> foobars) {

        //Do the regular stuff and return

    }
}

Non sono sicuro sulla risposta, ma vale la pena notare che asincrono e multi-threading sono cose diverse. Quindi sarebbe possibile avere un numero fisso di thread con gestione asincrona. Quello che succederebbe sarebbe quando una pagina dovesse bloccare per dire, I / O, un'altra pagina avrebbe la possibilità di essere eseguita sullo stesso thread. Ecco come entrambe queste affermazioni possono essere vere, l'asincrono può rendere le cose più veloci ma troppi thread sono un problema.
Chris Chilvers,

@ChrisChilvers Sì, il multithreading non è sempre necessario per il funzionamento asincrono. L'ho già immaginato, ma penso di non avere alcun controller su questo per quanto posso dire. AsyncController mostra quanti thread vuole dal mio punto di vista, ma non sono sicuro neanche su quello. C'è un'idea di threadpool anche su app desktop come WPF? Penso che il numero di thread non sia un problema per quel tipo di app.
Tugberk,

6
Guarda il video
Discussione

Penso che il problema (e quindi l'incoerenza) sia che la seconda affermazione usa asincrono quando significa molti thread. Ciò potrebbe essere dovuto al fatto che asp.net ha implementato le pagine asincrone e quindi l'implementazione specifica ha confuso il problema (dal momento che il nome della funzione che causa il problema sarebbe pagine asincrone), ma non sono sicuro dell'implementazione specifica . Quindi o significano "molti thread", o significano "pagine asincrone nella versione X di asp.net" poiché le versioni future potrebbero cambiare l'implementazione. Oppure intendono semplicemente usare il pool di thread per eseguire l'asincronizzazione all'interno di una pagina.
Chris Chilvers,

@ChrisChilvers oh, amico! Sono più confuso dopo questi commenti: s
tugberk,

Risposte:


177

Ecco un eccellente articolo che consiglierei di leggere per comprendere meglio l'elaborazione asincrona in ASP.NET (che è ciò che sostanzialmente rappresentano i controller asincroni).

Consideriamo innanzitutto un'azione sincrona standard:

public ActionResult Index()
{
    // some processing
    return View();
}

Quando viene effettuata una richiesta per questa azione, viene disegnato un thread dal pool di thread e il corpo di questa azione viene eseguito su questo thread. Quindi, se l'elaborazione all'interno di questa azione è lenta, stai bloccando questo thread per l'intera elaborazione, quindi questo thread non può essere riutilizzato per elaborare altre richieste. Al termine dell'esecuzione della richiesta, il thread viene restituito al pool di thread.

Ora prendiamo un esempio del modello asincrono:

public void IndexAsync()
{
    // perform some processing
}

public ActionResult IndexCompleted(object result)
{
    return View();
}

Quando una richiesta viene inviata all'azione Index, viene disegnato un thread dal pool di thread e IndexAsyncviene eseguito il corpo del metodo. Al termine dell'esecuzione del corpo di questo metodo, il thread viene restituito al pool di thread. Quindi, usando lo standard AsyncManager.OutstandingOperations, una volta che si segnala il completamento dell'operazione asincrona, viene estratto un altro thread dal pool di thread e il corpo IndexCompleteddell'azione viene eseguito su di esso e il risultato viene renderizzato al client.

Quindi ciò che possiamo vedere in questo modello è che una richiesta HTTP per singolo client potrebbe essere eseguita da due thread diversi.

Ora la parte interessante accade all'interno del IndexAsyncmetodo. Se hai un'operazione di blocco al suo interno, stai sprecando totalmente l'intero scopo dei controller asincroni perché stai bloccando il thread di lavoro (ricorda che il corpo di questa azione viene eseguito su un thread disegnato dal pool di thread).

Quindi, quando possiamo trarre vantaggio reale dai controller asincroni che potresti chiedere?

IMHO possiamo ottenere di più quando abbiamo operazioni di I / O intensive (come le chiamate di database e di rete a servizi remoti). Se hai un'operazione intensiva della CPU, le azioni asincrone non ti daranno molti vantaggi.

Quindi, perché possiamo trarre vantaggio dalle operazioni intensive di I / O? Perché abbiamo potuto usare Ports O di completamento di I / . IOCP è estremamente potente perché non si utilizzano thread o risorse sul server durante l'esecuzione dell'intera operazione.

Come funzionano?

Supponiamo di voler scaricare il contenuto di una pagina Web remota utilizzando il metodo WebClient.DownloadStringAsync . Si chiama questo metodo che registrerà un IOCP all'interno del sistema operativo e ritornerà immediatamente. Durante l'elaborazione dell'intera richiesta, non vengono utilizzati thread sul server. Tutto accade sul server remoto. Ciò potrebbe richiedere molto tempo, ma non ti interessa in quanto non stai mettendo a repentaglio i tuoi thread di lavoro. Una volta ricevuta una risposta, viene segnalato l'IOCP, un thread viene disegnato dal pool di thread e il callback viene eseguito su questo thread. Ma come puoi vedere, durante l'intero processo, non abbiamo monopolizzato alcun thread.

Lo stesso vale con metodi come FileStream.BeginRead, SqlCommand.BeginExecute, ...

Che dire di parallelizzare più chiamate al database? Supponiamo che tu abbia avuto un'azione di controller sincrono in cui hai eseguito 4 chiamate di database bloccanti in sequenza. È facile calcolare che se ogni chiamata al database impiega 200 ms, l'esecuzione del controller richiederà circa 800 ms.

Se non è necessario eseguire quelle chiamate in sequenza, parallelizzarle migliorerebbe le prestazioni?

Questa è la grande domanda, alla quale non è facile rispondere. Forse sì forse no. Dipenderà interamente dalla modalità di implementazione di tali chiamate al database. Se si utilizzano controller asincroni e porte di completamento I / O come discusso in precedenza, si aumenteranno le prestazioni di questa azione del controller e anche di altre azioni, poiché non si monopolizzeranno i thread di lavoro.

D'altra parte se le implementate male (con una chiamata al database di blocco eseguita su un thread dal pool di thread), fondamentalmente abbasserete il tempo totale di esecuzione di questa azione a circa 200 ms ma avreste consumato 4 thread di lavoro in modo da potrebbe aver degradato le prestazioni di altre richieste che potrebbero diventare carenti a causa della mancanza di thread nel pool per elaborarle.

Quindi è molto difficile e se non ti senti pronto per eseguire test estesi sulla tua applicazione, non implementare controller asincroni, poiché è probabile che tu faccia più danni che benefici. Implementali solo se hai un motivo per farlo: ad esempio hai identificato che le azioni del controller sincrono standard sono un collo di bottiglia per la tua applicazione (dopo aver eseguito test di carico e misurazioni estese ovviamente).

Ora consideriamo il tuo esempio:

public ViewResult Index() { 

    Task.Factory.StartNew(() => { 
        //Do an advanced looging here which takes a while
    });

    return View();
}

Quando viene ricevuta una richiesta per l'azione Index, viene disegnato un thread dal pool di thread per eseguire il suo corpo, ma il suo corpo pianifica solo una nuova attività usando TPL . Quindi l'esecuzione dell'azione termina e il thread viene restituito al pool di thread. Tranne quello, TPL usa i thread dal pool di thread per eseguire la loro elaborazione. Pertanto, anche se il thread originale è stato restituito al pool di thread, è stato disegnato un altro thread da questo pool per eseguire il corpo dell'attività. Quindi hai messo a repentaglio 2 fili dal tuo prezioso pool.

Consideriamo ora quanto segue:

public ViewResult Index() { 

    new Thread(() => { 
        //Do an advanced looging here which takes a while
    }).Start();

    return View();
}

In questo caso stiamo generando manualmente un thread. In questo caso, l'esecuzione del corpo dell'azione dell'Indice potrebbe richiedere un po 'più di tempo (perché la generazione di un nuovo thread è più costosa rispetto a quella di uno da un pool esistente). Ma l'esecuzione dell'operazione di registrazione avanzata verrà eseguita su un thread che non fa parte del pool. Quindi non stiamo mettendo a repentaglio i thread dal pool che rimangono liberi per soddisfare un'altra richiesta.


1
Davvero dettagliato, grazie! Supponiamo che, abbiamo 4 attività asincrone ( System.Threading.Task) in esecuzione all'interno del IndexAsyncmetodo. All'interno di tali operazioni, stiamo effettuando chiamate db verso un server. Quindi, tutte sono operazioni intensive di I / O, giusto? In tal caso, creiamo 4 thread separati (o otteniamo 4 thread separati dal pool di thread)? Supponendo che io abbia una macchina multi-core che funzioneranno anche in parallelo, giusto?
rimorchiatore

10
@tugberk, le chiamate al database sono operazioni di I / O, ma tutto dipenderà da come le implementerete. Se si utilizza una chiamata al database di blocco, ad esempio SqlCommand.ExecuteReadersi sta sprecando tutto poiché si tratta di una chiamata di blocco. Stai bloccando il thread su cui viene eseguita questa chiamata e se questo thread sembra essere un thread dal pool è molto male. Potrete usufruire solo se si utilizza I / O Ports Completamento: SqlCommand.BeginExecuteReader. Se non usi IOCP, non importa quello che fai, non utilizzare controller asincroni poiché farai più danni che benefici sulle prestazioni complessive della tua applicazione.
Darin Dimitrov,

1
Bene, la maggior parte delle volte uso prima il codice EF. Non sono sicuro che si adatti. Ho preparato un campione che mostra cosa faccio generalmente. Ho aggiornato la domanda, puoi dare un'occhiata?
Tugberk,

3
@tugberk, li stai eseguendo in parallelo, quindi il tempo totale di esecuzione è inferiore rispetto a quando li esegui in sequenza. Ma per eseguirli usi i thread di lavoro. Beh, in realtà EF è pigro, quindi quando lo fai _context.Foonon esegui nulla. Stai solo costruendo un albero delle espressioni. Stai estremamente attento con questo. L'esecuzione della query viene rinviata solo quando si inizia l'enumerazione sul set di risultati. E se ciò accade nella vista, ciò potrebbe essere catastrofico per la performance. Per eseguire con entusiasmo un'appendice di query EF .ToList()alla fine.
Darin Dimitrov,

2
@tugberk, avrai bisogno di uno strumento di test del carico per simulare più utenti in parallelo sul tuo sito web per vedere come si comporta sotto carico pesante. Mini Profiler non può simulare il carico sul tuo sito Web. Potrebbe aiutarti a vedere e ottimizzare le tue query ADO.NET e profilare un'unica richiesta che è inutile quando devi vedere come si comporta il tuo sito in una situazione del mondo reale quando molti utenti lo colpiscono.
Darin Dimitrov,

49

Sì - tutti i thread provengono dal pool di thread. L'app MVC è già multi-thread, quando arriva una richiesta, un nuovo thread verrà prelevato dal pool e utilizzato per soddisfare la richiesta. Quel thread sarà "bloccato" (da altre richieste) fino a quando la richiesta non sarà completamente revisionata e completata. Se non è disponibile alcun thread nel pool, la richiesta dovrà attendere fino a quando non sarà disponibile uno.

Se si dispone di controller asincroni ricevono comunque un thread dal pool ma durante la manutenzione della richiesta possono rinunciare al thread, in attesa che accada qualcosa (e quel thread può essere assegnato a un'altra richiesta) e quando la richiesta originale richiede un thread di nuovo ne prende uno dalla piscina.

La differenza è che se hai molte richieste di lunga durata (dove il thread è in attesa di una risposta da qualcosa) potresti esaurire i thread dal pool per soddisfare anche le richieste di base. Se disponi di controller asincroni, non hai più thread ma quei thread in attesa vengono restituiti al pool e possono soddisfare altre richieste.

Un esempio di vita quasi reale ... Pensa a come salire su un autobus, ci sono cinque persone in attesa di salire, la prima sale, paga e si siede (l'autista ha soddisfatto la sua richiesta), tu sali (l'autista sta riparando la tua richiesta) ma non riesci a trovare i tuoi soldi; mentre armeggi nelle tasche, l'autista si arrende e attira le due persone successive (soddisfacendo le loro richieste), quando trova i tuoi soldi l'autista inizia a trattare di nuovo con te (completando la tua richiesta) - la quinta persona deve aspettare fino hai finito ma la terza e la quarta persona sono state servite mentre eri a metà strada per essere servito. Ciò significa che il conducente è l'unico e unico thread della piscina e che i passeggeri sono le richieste. Era troppo complicato scrivere come avrebbe funzionato se ci fossero due driver ma puoi immaginare ...

Senza un controller asincrono, i passeggeri dietro di te dovrebbero aspettare anni mentre cercavi i tuoi soldi, nel frattempo l'autista dell'autobus non avrebbe fatto alcun lavoro.

Quindi la conclusione è che se molte persone non sanno dove sono i loro soldi (cioè richiedono molto tempo per rispondere a qualcosa che il guidatore ha chiesto) i controller asincroni potrebbero aiutare il throughput delle richieste, accelerando il processo da alcuni. Senza un controller aysnc tutti aspettano che la persona di fronte sia stata completamente trattata. MA non dimenticare che in MVC ci sono molti driver di bus su un singolo bus, quindi l'asincronizzazione non è una scelta automatica.


8
Molto bella analogia. Grazie.
Pittsburgh DBA,

Mi è piaciuta la descrizione. Grazie
Omer Cansizoglu,

Ottimo modo per spiegarlo. Grazie,
Anand Vyas,

La tua risposta in combinazione con la risposta di Darin riassume l'intero meccanismo dietro i controller asincroni, di cosa si tratta e, cosa più importante, di cosa non è!
Nirman,

Questa è una bella analogia, ma la mia unica domanda è questa: il tizio che frugava nelle tasche della tua analogia sarebbe una sorta di lavoro / elaborazione nella nostra applicazione ... quindi quali processi funzionano dopo aver rilasciato il thread? Sicuramente è un altro thread? Quindi cosa guadagniamo qui?
Tomuke,

10

Ci sono due concetti in gioco qui. Prima di tutto possiamo far eseguire il nostro codice in parallelo per eseguire più velocemente o programmare il codice su un altro thread per evitare che l'utente attenda. L'esempio che hai avuto

public ViewResult Index() { 

    Task.Factory.StartNew(() => { 
        //Do an advanced looging here which takes a while
    });

    return View();
}

appartiene alla seconda categoria. L'utente riceverà una risposta più rapida ma il carico di lavoro totale sul server è maggiore perché deve fare lo stesso lavoro + gestire il threading.

Un altro esempio di questo sarebbe:

public ViewResult Index() { 

    Task.Factory.StartNew(() => { 
        //Make async web request to twitter with WebClient.DownloadString()
    });

    Task.Factory.StartNew(() => { 
        //Make async web request to facebook with WebClient.DownloadString()
    });


    //wait for both to be ready and merge the results

    return View();
}

Poiché le richieste vengono eseguite in parallelo, l'utente non dovrà attendere finché verrà eseguito in serie. Ma dovresti capire che qui utilizziamo più risorse rispetto a quelle eseguite in seriale perché eseguiamo il codice su molti thread mentre abbiamo anche i thread in attesa.

Questo va perfettamente bene in uno scenario client. Ed è abbastanza comune lì avvolgere il codice sincrono di lunga durata in una nuova attività (eseguirlo su un altro thread) anche mantenere l'interfaccia utente reattiva o in parallelo per renderla più veloce. Tuttavia, viene comunque utilizzato un thread per l'intera durata. Su un server con carico elevato ciò potrebbe non funzionare perché si utilizzano effettivamente più risorse. Questo è ciò di cui la gente ti ha avvertito

I controller asincroni in MVC tuttavia hanno un altro obiettivo. Il punto qui è quello di evitare che le discussioni sui thread non facciano nulla (il che può danneggiare la scalabilità). Importa davvero solo se le API che stai chiamando hanno metodi asincroni. Come WebClient.DowloadStringAsync ().

Il punto è che puoi lasciare che il tuo thread sia restituito per gestire nuove richieste fino a quando la richiesta web non è finita dove ti chiamerà callback che ottiene lo stesso o un nuovo thread e termina la richiesta.

Spero che tu capisca la differenza tra asincrono e parallelo. Pensa al codice parallelo come al codice in cui si trova il tuo thread e attendi il risultato. Mentre il codice asincrono è il codice in cui sarai avvisato quando il codice è finito e puoi tornare a lavorarci, nel frattempo il thread può fare altro lavoro.


6

Le applicazioni possono essere ridimensionate meglio se le operazioni vengono eseguite in modo asincrono, ma solo se sono disponibili risorse per eseguire le operazioni aggiuntive .

Le operazioni asincrone assicurano che non stai mai bloccando un'azione perché ne è in corso una esistente. ASP.NET ha un modello asincrono che consente l'esecuzione simultanea di più richieste. Sarebbe possibile mettere in coda le richieste e le elabora FIFO, ma questo non si ridimensionerebbe bene quando ci sono centinaia di richieste in coda e ogni richiesta impiega 100 ms per l'elaborazione.

Se si dispone di un enorme volume di traffico, si potrebbe essere meglio non eseguendo le query in modo asincrono, come non ci possono essere ulteriori risorse per servire le richieste . Se non ci sono risorse di riserva, le tue richieste sono costrette a fare la fila, impiegare in modo esponenziale più lungo o fallire completamente, nel qual caso l'overhead asincrono (mutex e operazioni di cambio di contesto) non ti dà nulla.

Per quanto riguarda ASP.NET, non hai scelta: utilizza un modello asincrono, perché è ciò che ha senso per il modello server-client. Se dovessi scrivere internamente il tuo codice che utilizza un modello asincrono per tentare di ridimensionare meglio, a meno che tu non stia cercando di gestire una risorsa condivisa tra tutte le richieste, in realtà non vedrai alcun miglioramento perché sono già racchiusi in un processo asincrono che non blocca nient'altro.

In definitiva, è tutto soggettivo fino a quando non si osserva effettivamente cosa sta causando un collo di bottiglia nel sistema. A volte è ovvio dove un modello asincrono aiuterà (impedendo un blocco delle risorse in coda). In definitiva, solo misurare e analizzare un sistema può indicare dove è possibile ottenere efficienze.

Modificare:

Nel tuo esempio, la Task.Factory.StartNewchiamata metterà in coda un'operazione sul pool di thread .NET. La natura dei thread del pool di thread deve essere riutilizzata (per evitare il costo di creazione / distruzione di molti thread). Una volta completata l'operazione, il thread viene rilasciato nuovamente nel pool per essere riutilizzato da un'altra richiesta (Garbage Collector non viene effettivamente coinvolto a meno che tu non abbia creato alcuni oggetti nelle tue operazioni, nel qual caso vengono raccolti come di consueto scoping).

Per quanto riguarda ASP.NET, non vi sono operazioni speciali qui. La richiesta ASP.NET viene completata senza rispetto dell'attività asincrona. L'unica preoccupazione potrebbe essere se il pool di thread è saturo (ovvero non ci sono thread disponibili per soddisfare la richiesta in questo momento e le impostazioni del pool non consentono la creazione di più thread), nel qual caso la richiesta viene bloccata in attesa di avviare il compito fino a quando un filo piscina diventa disponibile.


Grazie! Dopo aver letto la tua risposta, ho modificato la domanda con un esempio di codice. Puoi dare un'occhiata?
rimorchiatore

Hai una frase magica lì per me: Task.Factory.StartNewcall metterà in coda un'operazione sul pool di thread .NET. . In questo contesto, quale è corretto qui: 1-) Crea un nuovo thread e quando è fatto, quel thread torna al threadpool e attende lì per essere riutilizzato di nuovo. 2-) Ottiene un thread dal threadpool e quel thread torna al threadpool e attende lì per essere riutilizzato di nuovo. 3-) Adotta l'approccio più efficiente e può fare uno di loro.
rimorchiatore

1
Il pool di thread crea thread quando sono necessari e li ricicla quando non vengono utilizzati. Il comportamento esatto è variato tra le versioni CLR. Puoi trovare informazioni specifiche al riguardo qui msdn.microsoft.com/en-us/library/0ka9477y.aspx
Paul Turner

Adesso inizia a prendere forma nella mia mente. Quindi, CLR possiede il pool di thread, giusto? Ad esempio, un'applicazione WPF ha anche una nozione di thread-pool e si occupa anche di lì-pool.
rimorchiatore

1
Il pool di thread è di per sé all'interno del CLR. Altri componenti che sono "a conoscenza" del pool stanno indicando che usano thread del pool di thread (ove appropriato) anziché creare e distruggere i propri. La creazione o la distruzione di un thread è un'operazione relativamente costosa, quindi l'utilizzo del pool è un grande guadagno di efficienza nelle operazioni di breve durata.
Paul Turner,

2

Sì, usano un thread dal pool di thread. In realtà esiste una guida piuttosto eccellente di MSDN che affronterà tutte le tue domande e altro ancora. L'ho trovato abbastanza utile in passato. Controlla!

http://msdn.microsoft.com/en-us/library/ee728598.aspx

Nel frattempo, i commenti + suggerimenti che senti sul codice asincrono dovrebbero essere presi con un granello di sale. Per cominciare, fare qualcosa di asincrono non significa necessariamente migliorarlo, e in alcuni casi può peggiorare la propria applicazione. L'altro commento che hai pubblicato su "un enorme volume di traffico ..." è corretto solo in determinati contesti. Dipende molto da cosa stanno facendo le tue operazioni e da come interagiscono con altre parti del sistema.

In breve, molte persone hanno molte opinioni su asincrono, ma potrebbero non essere corrette fuori contesto. Direi di concentrarti sui tuoi esatti problemi e fare test di prestazione di base per vedere quali controller asincroni, ecc. Gestiscono effettivamente con la tua applicazione.


Ho letto quel documento forse centinaia di volte e ho ancora tanta confusione (forse il problema sono io, chissà). Quando ti guardi intorno, vedi così tanti commenti incoerenti sull'asincronia su ASP.NET MVC come puoi vedere sulla mia domanda.
rimorchiatore

per l'ultima frase: all'interno di un'azione del controller, stavo interrogando un database 5 volte separatamente (dovevo farlo) e impiegavo circa 400 ms. Quindi, ho implementato AsyncController ed eseguirli in parallelo. Il tempo di risposta si è ridotto drasticamente a ca. 200 ms. Ma non ho idea di quanti thread crea, cosa succede a quei thread dopo che ho finito con loro, li GCarriva e li pulisce subito dopo che ho fatto in modo che la mia app non abbia una perdita di memoria, e così via. Qualche idea su quella parte.
rimorchiatore

collegare un debugger e scoprirlo.
AR

0

La prima cosa non è MVC ma l'IIS che gestisce il pool di thread. Pertanto, qualsiasi richiesta proveniente dall'applicazione MVC o ASP.NET viene gestita dai thread gestiti nel pool di thread. Solo con la creazione dell'app Asynch invoca questa azione in un thread diverso e rilascia immediatamente il thread in modo che possano essere prese altre richieste.

Ho spiegato lo stesso con un video di dettaglio ( http://www.youtube.com/watch?v=wvg13n5V0V0/ "Controller MVC Asynch e fame di thread") che mostra come avviene la fame di thread in MVC e come viene minimizzata utilizzando MVC Controller Asynch Ho anche misurato le code delle richieste usando perfmon in modo da poter vedere come le code delle richieste vengono ridotte per l'asincrono MVC e come peggiore per le operazioni di sincronizzazione.

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.