2010-03-21 13 views
18

Un modo per aumentare la scalabilità dell'applicazione server è eseguire l'operazione legata all'IO (lettura di file, socket, richieste Web, richieste database ecc.) In modo asincrono. Questo non significa eseguirli nel ThreadPool che bloccherà solo i thread mentre l'operazione è in esecuzione. Il modo corretto è utilizzare l'API asincrona (BeginRead, BeginGetResponse, BeginExecuteReader ecc.). Il problema è ben descritto nel libro CLR vi C#.Come posso eseguire le query di NHibenate in modo asincrono?

Ecco alcuni articoli su asynchronous queries in Linq to SQL.

Esistono modi per eseguire la query Nhibere in modo asincrono? Che dire di Linq a NHibernate?

Grazie, Andrey

+0

Il supporto 'async' sta arrivando per NHibernate 4.2.0 e 5.0.0. https://nhibernate.jira.com/browse/NH-3971 –

risposta

9

Purtroppo, no. NHibernate non espone l'implementazione interna dell'esecuzione del comando nel modo in cui funziona L2S.

Dovrai utilizzare il threadpool OPPURE creare una patch per NH per aggiungere il supporto di query asincrone. Sarebbe molto gradito dalla comunità e farebbe un buon esercizio (ma non è affatto banale)

+0

Futures + 1 compito lo fa abbastanza bene per tutti i database no? MARS (che è necessario per più chiamate asincrone) non è supportato (e davvero necessario?) Da alcuni database sql – Firo

+0

I futures non iniziano l'esecuzione. Sono solo un wrapper su multiqueries. –

+0

ne sono consapevole. Ecco perché ho scritto "+ compito". Vedere la mia risposta qui sotto per quello che intendo – Firo

12

Si noti che le chiamate al database asincrono NON implicano una migliore scalabilità complessiva da sole. Raccomando di leggere l'articolo "Should my database calls be Asynchronous?" per un'analisi approfondita. Ecco una citazione da tale articolo:

Una rispettato/Web architetto DB è andato in modo fino a dire:
per il database applicazioni che utilizzano le operazioni asincrone al ridurre il numero di thread bloccati sul server web è quasi sempre uno completa perdita di tempo. Un server web piccolo può gestire facilmente più richieste di blocco simultanee di rispetto allo il back-end del database può elaborare contemporaneamente . Invece assicurarsi che i chiamate di servizio sono a buon mercato presso il database , e limitare il numero di concomitanza esecuzione richieste a un certo numero che si è testato per funzionare correttamente e massimizzare il throughput complessivo transazione.

+8

questo argomento è diventato non valido a partire da agosto 2012 (dopo .net 4.5 rtm). ora che il costo del codice asincrono era significativamente ridotto, è assolutamente ok scrivere operazioni db in modo asincrono. ma in questo momento non c'è ancora supporto in NHibernate. spero che questo sia presto anche invaldato :) –

+9

@BorisBucha. NET 4.5 non ha nulla a che fare con questo. Solo perché è possibile esprimere più facilmente codice asincrono nel codice C# non significa che i server Web e i database siano automaticamente più scalabili. –

+6

credo che lo faccia. certo non puoi rendere il tuo DB più veloce semplicemente chiamandolo in modo asincrono, ma il tuo webserver è molto più facile da scalare verticalmente. Meno thread significano meno memoria. Se posso semplificare drasticamente l'argomento, potrei dire che, sfruttando l'asincronia, tu * vinci sempre. Le prestazioni rimangono le stesse nel peggiore dei casi. Nel migliore dei casi è possibile migliorarlo in modo significativo semplicemente vietando le attività associate a io di occupare Threadpool. E il costo di sviluppo è quasi nulla, quindi non vedo alcun motivo per non fare tutto in modo asincrono a partire da .net4.5. –

1

Sebbene non vi sia ancora supporto per le query asincrone in NH, è ancora possibile superare parzialmente alcuni degli effetti indesiderati delle chiamate in esecuzione (a lunga esecuzione) dal thread di richiesta.

Quello che vuoi è dividere Threadpool tra operazioni di breve durata e di lunga durata. Naturalmente questo non è possibile con l'effettiva implementazione di Threadpool e TPL, ma puoi aiutare te stesso abbastanza facilmente scrivendo la tua coda Producer/Consumer con elementi attendibili e concurrency personalizzate.

Si prega di dare un'occhiata a esempio ho messo insieme: https://gist.github.com/3746240

Codice è copia/incollato da grande libro "C# 5.0 in a Nutshell: il riferimento definitivo" di Joseph Albahari e Ben Albahari con modificazioni fatto da me facendo sì che lo scheduler crei thread di lavoro dedicati per l'acquisizione degli articoli.

+0

FYI, ricorda che Threadpool (e "attende Task.StartNew (...)" di conseguenza) ha una funzione di auto-crescita che quando sotto carico pesante puoi finire con molti thread dedicati e questa potrebbe essere una soluzione più desiderabile. onestamente, non ho fatto alcun confronto delle prestazioni della mia soluzione proposta rispetto al semplice threadpool vecchio con autogrow ma credo che potrebbe essere utile in alcuni casi (se si misura la perdita perf causata da autogrow lento in sé :)) –

11

più chiamate asincrone può essere riscritto con Future

var footask = QueryFooAsync(); 
var bartask = QueryBarAsync(); 
var baztask = QueryBazAsync(); 

var foos = await footask; 
var bars = await bartask; 
var baz = await baztask; 

// do something with foos, bars, baz 

può essere sostituito con

var foos = session.Query<Foo>().....ToFuture(); 
var bars = session.Query<Bar>().....ToFuture(); 
var baz = session.Query<Bazes>().....ToFutureValue(); 

await Task.Factory.StartNew(() => var ignored = baz.Value) // await the results 

// do something with foos, bars, baz 

questo ha anche il vantaggio nel codice asincrona che il tempo di andata e ritorno viene pagata una sola volta invece di 3 volte .

+1

Questo non è vero operazione asincrona e non suggerirei di farlo perché ora stai solo creando un altro thread. L'avvio di una nuova attività può essere utile se si desidera scaricare il lavoro associato alla cpu alla thread separata, ma la chiamata db è un'operazione di I/O e funziona meglio con async async. –

+0

@AndzejMaciusovic Hai ragione che non è veramente asincrono come liberare il thread ma blocca il thread molto più breve (1 roundtrip anziché 3) e può alleggerire il carico sul database perché gestisce solo 1 Request (con 3 query) . Vedere la risposta di Mauricio Scheffer sul perché il risparmio di CPU potrebbe non essere di grande aiuto. – Firo

Problemi correlati