Ciao a tutti,ho una applicazione *molto* multithread. :-) Non è una applicazione web, ma è (più o meno) un servizio windows, quindi ha un ciclo di vita teoricamente infinito.Diversi componenti hanno necessità di caricare e manipolare i dati,anche contemporaneamente.Tutti i componenti (quindi, anche attraverso threads diversi) accedonoalla stessa sessione.Facendo girare qualche test, ho ottenuto (con distribuzioneassolutamente casuale) divesre eccezioni del tipo:- NHibernate.Exceptions.GenericADOException: could not initialize acollection ... System.InvalidOperationException: Index was outsidebounds of the array- NHibernate.ADOException: There was a problem converting anIDataReader to NDataReader ---> SYstem.InvalidOperationException:Invalid attempt to call MetaData when reder is closedche vengono generate, come già detto, casualmente.Ora, mi chiedo, è possibile che sia la condivisione della sessione supiù thread a fare casino?In generale, esistono delle "best practices" per la gestione di similiscenari? E se creassi una sesssione per ogni thread?In questo caso, visto che ho oggetti che fanno parte di relazioni *-*che vanno in giro per il mondo (e quindi anche attraverso threaddifferenti) non avrei sempre problemi con le sessioni?Ciao e grazie,Giulio
LA Session di nhibernate no è thread safe, per cui non la puoi accedere da diversi thread. La soluzione è usare un ciclo di vita "session per thread" ed ogni tanto devi anche disposare la sessione altrimenti il consumo di memoria è mostruoso.
Io lavoro spesso in scenari di questo tipo, windows service e multithreading, solitamente il servizio gestisce "operazioni" nel mio caso ho uno scheduler che esegue delle azioni, ed adotto.
Ogni thread ha la sua session, al termine di ogni azione disposo la sessione cosi la azione successiva ha una session nuova.
alk.
--Blog Eng: http://www.codewrecks.com/blogBlog Ita: http://blogs.ugidotnet.org/rgmTwitter: http://twitter.com/alkampfer
Ciao Alk,
innanzitutto grazie per la risposta.
Gian Maria Ricci: Io lavoro spesso in scenari di questo tipo, windows service e multithreading, solitamente il servizio gestisce "operazioni" nel mio caso ho uno scheduler che esegue delle azioni, ed adotto.
...adotti cosa?
Gian Maria Ricci: Ogni thread ha la sua session, al termine di ogni azione disposo la sessione cosi la azione successiva ha una session nuova.
Alla fine, guardando bene il codice, ho isolato dei punti di thread safety, ho creato (più o meno) una sessione per thread e non ho più problemi. Inoltre uso le session solo per piccole operazioni localizzate, quindi non ho nemmeno un eccessivo utilizzo di memoria. Credo di essere sul punto di imbroccare la strada giusta (che è più un "credo di essere sul punto di acquisire la fomra mentis che mi serve)... ma ci sono ancora dei punti "oscuri".
Cito, ad esempio, un problema che mi sto ponendo. Ho un modello molto "connesso", una specie di matrice fatta così:
class Matrix {
IEnumerable <Column> ColumnSet { get; } IEnumerable <Row> RowSet { get; } void AddColumn(Column c); void AddRow(Row r);}class Column{ Matrix Matrix { ... } String Label { ... }}class Row{ Matrix Matrix { ... } IEnumerable<Element> ElementSet { get; } String Label { ... }}class Element { Int32 Value { get; } Row Row { get; } Column Column { get; }}
e nel mapping uso un @cascade che sia il più "comprensivo" possibile. Tenendo sue sessioni aperte in contemporanea, avevo eccezioni di tipo "Illegal attempt to associate a collection with two open sessions", quindi necessariamente devo far "viaggiare" gli oggetti da un thread all'altro dopo averli "staccati" dalla sessione (o avere terminato la stessa). Il mio problema è che devo *necessariamente* caricare sempre tutta la porzione di grafo (a meno di non starci mooooolto attento). In tal senso, esiste qualche best practice che ancora mi sfugge? ;-)
Ciao e grazie,
petrux
--
La situazione è questa, se tieni la sessione aperta, puoi usufruire del lazy load, ma chiaramente non da più thread, altrimenti ti porti dietro problemi. La soluzione di usare dto, è quella che risolve perchè ti fa caricare subito tutta la parte di grafo che ti serve, in maniera diciamo implicita. Per la thread safety comunque se devi passare oggetti da un thread ad un altro non puoi fare altrimenti.
Io la cosa che faccio è questa, carico dei dto da dei servizi, quindi sono oggetti non mappati, elaboro con tutti i thread che voglio, e poi alla fine salvo tutto il risultato richiamando un servizio e ripassando i dto aggiornati ed i nuovi dto, il servizio riapre la sessione e riaggiorna tutto in un singolo thread e non ho problemi.
non so se essere contento ma, a grandi linee, è lo stesso sistema che ho usato io. :-)
(anche se i Dto si chiamano descriptor).
Giulio