Thread di limitazione del pool di thread C #

Bene … Ho dato al sito una ricerca equa e ho letto molti post su questo argomento. Ho trovato questa domanda: il codice per un pool di thread semplice in C # è particolarmente utile.

Tuttavia, come sembra sempre, ciò di cui ho bisogno varia leggermente.

Ho esaminato l’esempio MSDN e l’ho adattato in qualche modo alle mie esigenze. L’esempio a cui mi riferisco è qui: http://msdn.microsoft.com/en-us/library/3dasc8as(VS.80,printer).aspx

Il mio problema è questo. Ho un set di codice abbastanza semplice che carica una pagina web tramite le classi HttpWebRequest e WebResponse e legge i risultati tramite uno Stream . Spengo questo metodo in un thread in quanto dovrà essere eseguito molte volte. Il metodo stesso è piuttosto breve, ma il numero di volte che deve essere licenziato (con dati vari per volta) varia. Può essere ovunque da 1 a 200.

Tutto ciò che ho letto sembra indicare che la class ThreadPool è il candidato principale. Ecco cosa le cose si complicano. Potrei aver bisogno di sparare questa cosa dire 100 volte, ma posso avere solo 3 thread al massimo in esecuzione (per questa particolare attività).

Ho provato a impostare MaxThreads sul ThreadPool tramite:

 ThreadPool.SetMaxThreads(3, 3); 

Non sono del tutto convinto che questo approccio funzioni. Inoltre, non voglio clobber altri siti Web o programmi in esecuzione sul sistema su cui verrà eseguito. Quindi, limitando il numero di thread sul ThreadPool , posso essere certo che questo riguarda solo il mio codice e le mie discussioni?

L’esempio MSDN utilizza l’approccio unità evento e chiama WaitHandle.WaitAll(doneEvents); che è come sto facendo questo.

Quindi il cuore della mia domanda è, come si fa a garantire o specificare un numero massimo di thread che possono essere eseguiti per il loro codice, ma il codice continua a far girare più thread mentre i precedenti finiscono fino a qualche punto arbitrario? Sto affrontando questo nel modo giusto?

Cordiali saluti,

Jason


Ok, ho aggiunto un approccio con il semaforo e rimosso completamente il codice ThreadPool . Sembra abbastanza semplice. Ho ricevuto le mie informazioni da: http://www.albahari.com/threading/part2.aspx

È questo esempio che mi ha mostrato come:

[testo qui sotto è una copia / incolla dal sito]

Un Semaphore con una capacità di uno è simile a un Mutex o un lock , tranne per il fatto che il Semaphore non ha “proprietario” – è indipendente dal thread. Qualsiasi thread può chiamare Release su un Semaphore , mentre con Mutex e lock , solo il thread che ha ottenuto la risorsa può rilasciarlo.

Nel seguente esempio, dieci thread eseguono un ciclo con un’istruzione Sleep nel mezzo. Un Semaphore garantisce che non più di tre thread possano eseguire l’istruzione Sleep contemporaneamente:

 class SemaphoreTest { static Semaphore s = new Semaphore(3, 3); // Available=3; Capacity=3 static void Main() { for (int i = 0; i < 10; i++) new Thread(Go).Start(); } static void Go() { while (true) { s.WaitOne(); Thread.Sleep(100); // Only 3 threads can get here at once s.Release(); } } } 

Nota: se si limita questo a “3” solo per non sovraccaricare la macchina che esegue l’app, farei in modo che questo sia un problema. Il threadpool dovrebbe gestirlo per te. D’altra parte, se non vuoi travolgere qualche altra risorsa, allora continua a leggere!


Non è ansible gestire la dimensione del threadpool (o molto altro su di esso).

In questo caso, utilizzerei un semaforo per gestire l’accesso alla tua risorsa. Nel tuo caso, la tua risorsa sta eseguendo il web scrap, o calcolando alcuni report, ecc.

Per fare ciò, nella class statica, crea un object semaforo:

 System.Threading.Semaphore S = new System.Threading.Semaphore(3, 3); 

Quindi, in ogni thread, lo fai:

 System.Threading.Semaphore S = new System.Threading.Semaphore(3, 3); try { // wait your turn (decrement) S.WaitOne(); // do your thing } finally { // release so others can go (increment) S.Release(); } 

Ogni thread si bloccherà su S.WaitOne () fino a quando non verrà dato il segnale per procedere. Una volta che S è stato decrementato 3 volte, tutti i thread si bloccheranno fino a quando uno di essi incrementa il contatore.

Questa soluzione non è perfetta.


Se vuoi qualcosa di un po ‘più pulito e più efficiente, ti consiglio di andare con un approccio BlockingQueue in cui accodare il lavoro che vuoi eseguire in un object globale di coda di blocco.

Nel frattempo, hai tre thread (che hai creato, non nel threadpool), che escono dalla coda per essere eseguiti. Non è così complicato da configurare ed è molto veloce e semplice.

Esempi:

  • Migliore esempio di coda di threading / best practice
  • Il miglior metodo per ottenere oggetti da un BlockingQueue in un programma concorrente?

È una class statica come qualsiasi altra, il che significa che qualsiasi cosa tu faccia con essa influenza ogni altro thread nel processo corrente. Non influenza altri processi.

Tuttavia, considero questo uno dei difetti di progettazione più grandi in .NET. Chi ha avuto la brillante idea di rendere statico il pool di thread? Come mostra il tuo esempio, spesso vogliamo un pool di thread dedicato al nostro compito, senza che questo interferisca con attività non correlate in altre parti del sistema.