2011-01-07 17 views
6

Ho utilizzato Spring.NET e NHibernate da alcuni anni e sono molto soddisfatto. Tuttavia, mi sono sempre divertito con il multi threading, le Reactive Extensions e infine Task Parallel Library, che è un ottimo framework. Sfortunatamente tutti i tipi di approccio al multithreading falliscono a causa della sessione di NHiberntate che non è thread-safe.Attività C# Libreria parallela e NHibernate/Spring.NET

Ti chiedo come posso beneficiare della programmazione parallela e utilizzare ancora NHibernate.

Per esempio: Ho una classe CustomerRegistrationService quale metodo Register svolge diversi compiti:

ICustumer customer = this.CreateCustomerAndAdresses(params); 
this.CreateMembership(customer); 
this.CreateGeoLookups(customer.Address); 
this.SendWelcomeMail(customer); 

Gli ultimi due metodi sarebbero candidati ideali per l'esecuzione in parallelo, CreateGeoLookups chiama alcuni servizi web per determinare posizioni geo del cliente del indirizza e crea alcune nuove entità e aggiorna il cliente stesso. SendWelcomMail fa quello che dice.

Perché CreateGeoLookups utilizza NHibernate (sebbene attraverso gli oggetti repository in modo che NHibernate sia acutamente nascosto tramite Interfaces/Dependency Inection) non funzionerà con Task.Factory.StarNew (...) o altri meccanismi di threading.

La mia domanda non è quella di risolvere proprio questo problema che ho descritto, ma mi piacerebbe sentire da voi su NHibenrate, Spring.NET e approcci paralleli.

ringrazio molto Max

risposta

8

in NH sua l'ISession che non è thread-safe, ma l'ISessionFactory è completamente thread-safe, facilmente sostenere ciò che sembra siete dopo. Se hai progettato la gestione del ciclo di vita della sessione (e dei repository che dipendono da esso) in modo tale da assumere un'unica ISessione coerente tra le chiamate, allora sì, avrai questo tipo di problemi. Ma se hai progettato il tuo modello di gestione delle sessioni per assumere solo una singola ISessionFactory ma non per fare supposizioni su ISession, allora non c'è nulla che ti impedisca di interagire con NH in parallelo.

Anche se non si menziona espressamente il caso d'uso come web, è importante prendere nota che nei casi di utilizzo incentrati sul web (ad esempio, ciò che è un caso piuttosto comune per gli utenti Spring.NET e molti altri framework NH-managing), il modello di gestione delle sessioni "Session-Per-Request" usato spesso (spesso indicato in Spring.NET come 'Open Session In View' o solo 'OSIV') NON funzionerà e tu dovrà passare a una diversa durata del tuo ciclo di vita dell'ISession. Questo perché (come suggerisce il nome) il pattern sessione per richiesta/OSIV rende l'ipotesi (ora errata nel tuo caso) che esiste una sola istanza di ISession per la durata di ogni HttpRequest (e presumibilmente vorrai essere generando queste chiamate parallele, NH chiama tutto nel contesto di un singolo HttpRequest nel caso di utilizzo del web).

Ovviamente nel caso non Web in cui raramente esiste un concetto simile a sessione per richiesta, non è probabile che ci si imbatta in questo problema poiché la gestione del ciclo di vita della sessione è raramente come a grana fine/di breve durata come nelle applicazioni web-based.

Spero che questo aiuti.

-Steve B.

0

Bene, grazie per la risposta. So che l''ISession non è thread-safe ma ISessionFactory è interamente thread-safe'. Il mio problema nel codice precedente, ad esempio, è che l'intera operazione è racchiusa in un'unica transazione. Quindi this.CreateCustomerAndAdresses (params) sul thread principale # 1 userà per esempio l'ISession # 1 con la transazione # 1.Chiamando gli altri tre in parallelo creeremo altri tre thread e altre tre sessioni e transazioni che portano al timeout del database nel mio caso. La mia ipotesi è che la transazione n. 1 non venga eseguita correttamente perché attende che le tre attività simultanee vengano completate. Ma le tre attività concorrenti tentano di leggere dal database mentre una transazione è ancora attiva e porta a deadlock/timeout.

Quindi c'è un modo per dire agli altri thread/sessioni di non creare una nuova transazione ma utilizzare la transazione principale # 1?

Sto utilizzando il TxScopeTransactionManager da Spring.NET che utilizza DTC (System.Transactions). Ho cercato su google che forse System.Transactions.DependentTransaction potrebbe funzionare ma non ho idea di come integrarlo nel mio scenario gestito di transazione Spring.NET.

Grazie

+0

Dovresti davvero modificare la tua domanda principale con questa domanda. Qualcuno di questi ha funzionato come risposta? – paqogomez

2

Questa è una cosa difficile che chiedi. Il DTC deve essere preso con cura.

L'unica soluzione che posso sapere è l'uso di messaggistica transazionale affidabile (ad esempio MSMQ + NServiceBus/MassTransit).

Tale design consente di eseguire questa operazione. Si sarebbe simile a questa:

var customerUid=CreateCustomers(); 
Bus.Publish(new CustomerCreatedEvent() { CustomerUid = customerUid}); 

allora si potrebbe utilizzare due gestori di eventi (reattori) che gestiscono l'evento e inviare una e-mail o creare le ricerche.

Questo non ti consentirà di condividere la Transazione ma assicurerà che i Reattori siano eseguiti (in una nuova Transazione) quando la creazione del cliente è stata superata. Anche questo non ha nulla a che fare con il TPL.

+0

Per il problema dichiarato, credo davvero che questo sia l'approccio più ragionevole. Non vorrai creare il cliente perché non potresti creare i dati geografici o inviare una e-mail, piuttosto vorrai riprovare entrambi quei processi fino al loro completamento. Questo è perfetto per l'architettura della coda dei messaggi. –

Problemi correlati