Qual è il modo migliore per passare i dati tra thread simultanei in .NET?
-
01-07-2019 - |
Domanda
Ho due thread, uno deve sondare un sacco di risorse statiche separate in cerca di aggiornamenti. L'altro deve ottenere i dati e archiviarli nel database. Come può il thread 1 dire al thread 2 che c'è qualcosa da elaborare?
Soluzione
Se i pezzi di dati sono indipendenti, trattarli come elementi di lavoro che devono essere elaborati da un pool di thread. Utilizzare il pool di thread e QueueUserWorkItem
per pubblicare i dati nei thread. Dovresti ottenere una migliore scalabilità utilizzando un pool di thread simmetrici e limitando la quantità di sincronizzazione che deve avvenire tra produttore e consumatore.
Ad esempio (da MSDN ):
TaskInfo ti = new TaskInfo("This report displays the number {0}.", 42);
// Queue the task and data.
if (ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc), ti)) {
Console.WriteLine("Main thread does some work, then sleeps.");
// If you comment out the Sleep, the main thread exits before
// the ThreadPool task has a chance to run. ThreadPool uses
// background threads, which do not keep the application
// running. (This is a simple example of a race condition.)
Thread.Sleep(1000);
Console.WriteLine("Main thread exits.");
}
else {
Console.WriteLine("Unable to queue ThreadPool request.");
}
// The thread procedure performs the independent task, in this case
// formatting and printing a very simple report.
//
static void ThreadProc(Object stateInfo) {
TaskInfo ti = (TaskInfo) stateInfo;
Console.WriteLine(ti.Boilerplate, ti.Value);
}
Altri suggerimenti
Uso Monitor.Wait / Pulse su una coda di elementi di lavoro.
Il " memorizza nel DB " thread deve sempre essere in esecuzione? Sembra che forse l'opzione migliore (se possibile) sarebbe quella di far girare il thread di polling su un altro thread per fare il salvataggio. A seconda del numero di thread creati, tuttavia, è possibile che il primo thread di polling utilizzi ThreadPool.QueueUserWorkItem () potrebbe essere la route più efficiente.
Per maggiore efficienza, durante il salvataggio nel database, utilizzerei l'I / O asincrono sul DB anziché i metodi di sincronizzazione.
Ogni volta che riesci a evitare di dover comunicare direttamente tra due thread, dovresti. Dovendo mettere insieme alcune primitive di sincronizzazione, il tuo codice non sarà così facile da eseguire il debug e potrebbe introdurre alcune condizioni di gara molto sottili che causano "una volta su un milione di esecuzioni". tipo di bug (che sono tutt'altro che divertenti da trovare / correggere).
Se il secondo thread deve sempre essere in esecuzione, facci sapere perché con alcune informazioni aggiuntive e possiamo tornare con una risposta più approfondita.
Buona fortuna!
Personalmente avrei degli eventi di rilancio del thread 1 a cui il thread 2 può rispondere. I thread possono essere collegati agli eventi appropriati tramite il processo di controllo che avvia entrambi i thread.