[C#] Ci sono casi in cui è preferibile utilizzare un semplice oggetto Thread vecchio invece di uno dei costrutti più recenti?


Answers

I thread sono un elemento fondamentale per certe cose (ovvero il parallelismo e l'asincronia) e quindi non dovrebbero essere portati via. Tuttavia , per la maggior parte delle persone e la maggior parte dei casi d'uso ci sono cose più appropriate da usare che hai menzionato, come i pool di thread (che forniscono un bel modo di gestire molti piccoli lavori in parallelo senza sovraccaricare la macchina generando 2000 thread contemporaneamente), BackgroundWorker (che racchiude eventi utili per un singolo pezzo di lavoro di breve durata).

Ma solo perché in molti casi quelli sono più appropriati in quanto schermano il programmatore dall'inutile reinventare la ruota, facendo errori stupidi e simili, ciò non significa che la classe Thread sia obsoleta. È ancora usato dalle astrazioni sopra menzionate e ne avresti ancora bisogno se hai bisogno di un controllo preciso sui thread che non sono coperti dalle classi più speciali.

Analogamente, .NET non vieta l'uso di matrici, nonostante List<T> sia una soluzione migliore per molti casi in cui le persone utilizzano array. Semplicemente perché potresti ancora voler costruire cose che non sono coperte dalla lib standard.

Question

Vedo un sacco di persone nei post dei blog e qui su SO evito o sconsigliamo l'uso della classe Thread nelle ultime versioni di C # (e intendo, naturalmente, 4.0+, con l'aggiunta di Task e amici). Ancor prima, c'erano dibattiti sul fatto che una funzionalità di thread vecchio semplice può essere sostituita in molti casi dalla classe ThreadPool .

Inoltre, altri meccanismi specializzati rendono la classe Thread meno attraente, come Timer che sostituisce la brutta combinazione Thread + Sleep , mentre per le GUI abbiamo BackgroundWorker , ecc.

Tuttavia, il Thread sembra rimanere un concetto molto familiare per alcune persone (me compreso), persone che, quando devono confrontarsi con un'attività che implica una sorta di esecuzione parallela, salta direttamente all'utilizzo della buona vecchia classe Thread . Mi sono chiesto ultimamente se è ora di modificare i miei modi.

Quindi la mia domanda è, ci sono dei casi in cui è necessario o utile usare un semplice oggetto Thread vecchio invece di uno dei costrutti sopra?




Ho sempre usato la classe Thread quando ho bisogno di contare e controllare i thread che ho attivato. Mi rendo conto che potrei usare il threadpool per conservare tutto il mio lavoro eccezionale, ma non ho mai trovato un buon modo per tenere traccia di quanto lavoro è attualmente in corso o di quale sia lo stato.

Invece, creo una raccolta e inserisco i thread in essi dopo che li ho girati: l'ultima cosa che fa un thread è rimuovere se stessa dalla raccolta. In questo modo, posso sempre dire quanti thread sono in esecuzione e posso usare la raccolta per chiedere a ciascuno cosa sta facendo. Se c'è un caso in cui ho bisogno di ucciderli tutti, normalmente dovresti impostare un qualche tipo di flag "Abort" nella tua applicazione, attendere che ogni thread lo noti da solo e si auto-termini - nel mio caso, io può percorrere la raccolta ed emettere un Thread.Abort a ciascuno a turno.

In tal caso, non ho trovato un modo migliore per lavorare direttamente con la classe Thread. Come ha detto Eric Lippert, gli altri sono solo astrazioni di livello superiore ed è appropriato lavorare con le classi di livello inferiore quando le implementazioni di alto livello disponibili non soddisfano le tue necessità. Proprio come a volte è necessario effettuare chiamate API Win32 quando .NET non soddisfa le tue esatte esigenze, ci saranno sempre casi in cui la classe Thread è la scelta migliore nonostante i recenti "progressi".




È possibile confrontare la classe Thread con ADO.NET. Non è lo strumento consigliato per portare a termine il lavoro, ma non è obsoleto. Altri strumenti si basano su di esso per facilitare il lavoro.

Non è sbagliato usare la classe Thread su altre cose, specialmente se queste cose non forniscono una funzionalità di cui hai bisogno.




Per rispondere alla domanda " ci sono dei casi in cui è necessario o utile usare un semplice oggetto Thread vecchio ", direi che un semplice thread vecchio è utile (ma non necessario) quando si ha un processo di lunga durata che hai vinto " mai interagire con una discussione diversa

Ad esempio, se stai scrivendo un'applicazione che si abbona per ricevere messaggi da una sorta di coda di messaggi e l'applicazione sta per fare qualcosa di più che elaborare solo quei messaggi, sarebbe utile usare una discussione perché il thread sarà autosufficiente (cioè non stai aspettando che funzioni), e non è di breve durata. L'utilizzo della classe ThreadPool è più utile per mettere in coda una serie di elementi di lavoro di breve durata e consentire alla classe ThreadPool di gestire in modo efficiente l'elaborazione di ciascuno come una nuova discussione è disponibile. Le attività possono essere utilizzate dove si utilizza Thread direttamente, ma nello scenario sopra non credo che ti comprerebbero molto. Ti aiutano a interagire con il thread più facilmente (che lo scenario sopra non ha bisogno) e aiutano a determinare quanti thread effettivamente dovrebbero essere usati per il set dato di attività in base al numero di processori che hai (che non è quello che vuoi, quindi diresti al Task che la tua cosa è LongRunning, nel qual caso nell'attuale implementazione 4.0 creerebbe semplicemente un thread separato non raggruppato).




La classe Thread non è obsoleta, è comunque utile in circostanze particolari.

Dove lavoro abbiamo scritto un "processore in background" come parte di un sistema di gestione dei contenuti: un servizio Windows che monitora directory, indirizzi e-mail e feed RSS e ogni volta che qualcosa di nuovo mostra esegue un'attività su di esso - in genere per importare dati.

I tentativi di utilizzare il pool di thread per questo non ha funzionato: tenta di eseguire troppe cose contemporaneamente e di eliminare i dischi, quindi abbiamo implementato il nostro sistema di polling ed esecuzione utilizzando direttamente la classe Thread .