2009-03-26 15 views
26

Nella programmazione .NET multithread, quali sono i criteri decisionali per l'utilizzo di ThreadPool.QueueUserWorkItem rispetto all'avvio del mio thread tramite nuova Thread() e Thread.Start()?Vantaggio dell'utilizzo di Thread.Start vs QueueUserWorkItem

In un'app server (diciamo, un'app ASP.NET o un servizio WCF) Penso che il ThreadPool sia sempre lì e disponibile. Cosa succede in un'app client, come un'app WinForms o WPF? C'è un costo per far ruotare il pool di thread? Se voglio solo 3 o 4 thread lavorare per un breve periodo su alcuni calcoli, è meglio per QUWI o per Thread.Start().

risposta

21

Il ThreadPool è sempre presente, tuttavia, vi è un numero finito di thread assegnati al pool in base al numero di processori. Per le applicazioni ASP.NET, è generalmente una cattiva idea usare Threads a meno che non si stia iniziando un processo Async e si sappia che non ci sarà un gran numero di richieste (ricordate che ci sono un numero finito di thread nel ThreadPool che condividi con tutto ciò che è in esecuzione nel tuo AppDomain e c'è un limite realistico sul numero totale di thread che vuoi creare usando anche il nuovo Thread()).

Per le app WinForms considerare l'utilizzo di BackgroundWorker anziché utilizzare un Thread o il ThreadPool. Utilizza il ThreadPool, tuttavia, rende più facile la comunicazione tra thread sul programmatore esperto multi-thread.

Aggiornato

Evitare di utilizzare ThreadPool.QueueUserWorkItem come la vostra piscina app potrebbe scomparire in qualsiasi momento. Sposta questo lavoro all'esterno o usa WebBackgrounder se devi.

Da Hanselman.com - "Checklist: What NOT to do in ASP.NET"

4

Questa discussione vi interesserà
When should I not use the ThreadPool in .Net?

+0

Non ho tratto alcun beneficio da quella discussione, che sembrava essere principalmente un dibattito sul costo di iniziare una discussione. – Cheeso

+0

Pensavo che il link fosse fantastico. Non ho visto nulla sul costo di iniziare un thread nella risposta accettata - ma diverse limitazioni del threadpool sono enumerate abbastanza bene lì. – BrainSlugs83

1

Il pool di thread è sempre disponibile in applicazioni .NET, indipendentemente dal tipo.

Il costo per l'avvio di una discussione dal pool di thread tramite ThreadPool.QueueUserWorkItem non sarà superiore al costo dell'avvio del proprio thread e potrebbe essere inferiore.

Se si desidera solo alcuni thread per un breve periodo, utilizzare il pool di thread. Ecco a cosa serve

2

Se i compiti sono di breve è molto probabile vedere molto migliore performance dalle attività di pianificazione sul pool di thread tramite QueueUserWorkItem o BeginInvoke come si evita il costo ripetuto di creare e distruggere le proprie discussioni.

Il pool di thread ovviamente paga anche per la creazione di thread, ma riutilizza i thread, quindi non si paga il costo per attività.

Si consiglia inoltre di dare un'occhiata a Threading in C# (ebook gratuito).

0

Se si creano i propri thread, è consigliabile avviarli al primo utilizzo e lasciarli in attesa per un po 'nel caso in cui ne siano necessari di nuovo - si fa in attesa un thread inattivo su un evento in modo che sia possibile riattivarlo segnalando l'evento e, trascorso un tempo sufficientemente lungo, il thread si risveglierà e uscirà, recuperando le risorse inutilizzate.Mantenendo un piccolo numero di thread inattivi pronti per essere riutilizzati, si riduce il sovraccarico di creare e distruggere costantemente i thread (che è significativo per operazioni sufficientemente brevi).

Ma questo è fondamentalmente ciò che la coda di thread già fa per te, quindi puoi anche usarlo. È un problema risolto.

Un dibattito simile si verificava nella comunità C++ sugli stringhe, che ci crediate o meno. Dovremmo scrivere ognuno la nostra classe di stringhe, o dovremmo usare std::string? La risposta dipende se vuoi imparare come scrivere una classe di stringhe, o hai finito e vuoi continuare a inventare qualcosa di nuovo.

+0

Per il problema che descrivi, l'utilizzo del modello di programmazione asincrono è molto più desiderabile e utilizza il flusso i di ThreadPool e non consuma risorse aggiuntive durante il periodo di inattività. –

14

Stavo per fare un commento, ma è passato troppo tempo.
CodemonkeyKing sembra aver raggiunto un punto importante, anche se non abbastanza forte secondo me.

Ci sono molti criteri che è possibile utilizzare per descrivere il codice. Verrà utilizzato in un'app funzionante o no? App Winforms o no? È un'app Server o client? libreria o exe standalone? ecc. ecc.

Mi sembra che se il codice verrà eseguito in un'app standalone e si avrà il controllo su tutto il codice circostante, sarà possibile rollare il proprio pool di thread, avviare i propri thread e misurare e gestire il costo attorno all'avvio del thread, alla latenza dei thread e al consumo delle risorse. O potresti usare la QUWI, ma non ucciderà la tua app in alcun modo. Sei libero di scegliere.

D'altra parte se il codice è impacchettato come una libreria che può essere utilizzata in un server - in ASP.NET, o forse in un'app CLR SQL o in un servizio WCF - allora è una pessima idea creare discussioni. È necessario utilizzare QUWI o qualche altro meccanismo che sfrutta il pool di thread incorporato (come BackgroundWorker). Se deve essere utilizzato nelle app lato client con altre librerie, ancora una volta, è necessario QUWI. Immagina che tutte le librerie che vogliono sfruttare i computer multi-core facciano rotolare i propri thread. Ci sarebbe il caos completo nelle app che utilizzavano più di poche librerie. Fili rampanti, tutti in competizione per le stesse risorse. Nessuna coordinazione centrale dei processori #threads vs #.

Buono hygeine richiede che una biblioteca, se è per essere consumato in applicazioni client o applicazioni del server, utilizza il ThreadPool comuni, e questo significa QUWI.

L'ultima cosa da capire è questa;

Un thread gestito è un thread in background o un thread in primo piano. I thread in background sono identici ai thread in primo piano con un'eccezione: un thread in background non mantiene attivo l'ambiente di esecuzione gestito. Una volta che tutti i thread in primo piano sono stati interrotti in un processo gestito (in cui il file .exe è un assembly gestito), il sistema interrompe tutti i thread in background e si arresta.

I thread che appartengono al pool di thread gestito (ovvero i thread la cui proprietà IsThreadPoolThread è true) sono thread in background. Tutti i thread che entrano nell'ambiente di esecuzione gestito dal codice non gestito sono contrassegnati come thread in background. Tutti i thread generati dalla creazione e dall'avvio di un nuovo oggetto Thread sono per impostazione predefinita i thread in primo piano.

Se si utilizza un thread per monitorare un'attività, ad esempio una connessione socket, impostare la proprietà IsBackground su true in modo che il thread non impedisca la chiusura del processo.

dal MSDN site.

2

Ecco un altro vantaggio nell'utilizzo di ThreadPool.QueueUserWorkItem.

Ho un'app winforms che ha un battito cardiaco. Inizialmente ho implementato questo utilizzando

  heartbeat = new Thread(HeartbeatDoWork); 
     heartbeat.Start(); 

Che funziona bene il 98% del tempo. Tuttavia, quando l'app viene chiusa, a volte non "muore" correttamente, ovvero il processo è ancora visibile nel task manager.

Per essere brevi, l'heartbeat ha pubblicato un evento e stava gestendo l'evento (CAB pub/sub) in cui era "bloccato".

La correzione è stato facile, basta cambiare di utilizzare questo

  ThreadPool.QueueUserWorkItem(HeartbeatDoWork); 

Sono sicuro che ci sono un paio di cose in più avrei potuto fare quando a girare il mio proprio thread e alla sarebbe stata pulita correttamente, ma questo è più semplice, più veloce e più facile da capire ... il ThreadPool fa tutto il lavoro per me.

+9

forse dovresti aver aggiunto la linea: heartbeat.IsBackground = true; –

0

Un vantaggio dell'utilizzo di Thread.Start() è che, , è possibile interrompere intenzionalmente il thread in un secondo momento. Nel ThreadPool non hai modo di controllare l'esecuzione del thread dopo averlo accodato.

+0

È a mia conoscenza che in generale l'utilizzo di Thread.Abort è una cattiva idea perché può perdere risorse che potrebbero non essere mai state rimosse. L'unica volta che dovrebbe essere utilizzata è quando l'applicazione si chiude forzatamente, a causa di uno stato di errore irreversibile. – devios1

+0

È possibile annullare alcune operazioni 'ThreadPool'. Vedi [this] (http://stackoverflow.com/questions/7731610/cancel-threadpool-queueuserworkitem-task). –

0

La maggior parte della mia lettura concorda con Marcel, la possibilità di controllare il thread se qualcosa va (abortire ...) è qualcosa che dovrebbe essere considerato pesantemente in particolare se si tratta di chiamate di terze parti su cui non si ha il controllo appendere.

+0

Più come un commento! – Nitesh

Problemi correlati