Domanda

Qual è la differenza tra l'utilizzo di un nuovo thread e l'utilizzo di un thread dal pool di thread? Quali sono i vantaggi in termini di prestazioni e perché dovrei prendere in considerazione l'utilizzo di un thread dal pool anziché di uno che ho creato esplicitamente? Sto pensando specificamente a .NET qui, ma esempi generali vanno bene.

È stato utile?

Soluzione

Il pool di thread offrirà vantaggi per operazioni frequenti e relativamente brevi entro

  • Riutilizzare i thread che sono già stati creati anziché crearne di nuovi (un processo costoso)
  • Limitare la velocità di creazione del thread quando c'è un'esplosione di richieste per nuovi elementi di lavoro (credo che questo sia solo in .NET 3.5)

    • Se si mettono in coda 100 attività del pool di thread, verranno utilizzati solo tutti i thread già creati per soddisfare queste richieste (ad esempio 10). Il pool di thread effettuerà controlli frequenti (credo ogni 500ms in 3.5 SP1) e se ci sono attività in coda, creerà un nuovo thread. Se le tue attività sono veloci, il numero di nuovi thread sarà ridotto e riutilizzando i 10 thread circa per le attività brevi sarà più veloce della creazione di 100 thread in anticipo.

    • Se il carico di lavoro ha costantemente un numero elevato di richieste di pool di thread in arrivo, il pool di thread si sintonizzerà sul carico di lavoro creando più thread nel pool con il processo sopra in modo che vi sia un numero maggiore di thread disponibile per elaborare le richieste

    • check Qui per informazioni più approfondite su come funziona il pool di thread sotto il cofano

La creazione di un nuovo thread da soli sarebbe più appropriata se il lavoro fosse relativamente lungo (probabilmente circa un secondo o due, ma dipende dalla situazione specifica)

@Krzysztof - I thread del pool di thread sono thread in background che si interromperanno al termine del thread principale. I thread creati manualmente sono in primo piano per impostazione predefinita (continueranno a funzionare dopo che il thread principale è terminato), ma possono essere impostati in background prima di chiamare Avvia su di essi.

Altri suggerimenti

Il pool di thread gestiti .NET: -

  • Si dimensiona in base al carico di lavoro corrente e all'hardware disponibile
  • Contiene thread di lavoro e thread della porta di completamento (che sono specificamente utilizzati per servire l'IO)
  • È ottimizzato per un gran numero di operazioni di breve durata

Esistono altre implementazioni del pool di thread che potrebbero essere più appropriate per operazioni di lunga durata.

In particolare, utilizzare un pool di thread per impedire all'app di creare troppi thread. La caratteristica più importante di un threadpool è la coda di lavoro. Cioè, una volta che la tua macchina è sufficientemente occupata, il pool di thread accoderà le richieste anziché generare immediatamente più thread.

Quindi, se creerai un numero limitato e limitato di thread, creali tu stesso. Se non riesci a determinare anticipatamente quanti thread potrebbero essere creati (ad es. Sono creati in risposta all'IO in entrata) e il loro lavoro avrà vita breve, usa il pool di thread. Se non sai quanti, ma il loro lavoro durerà a lungo, non c'è nulla nella piattaforma che ti possa aiutare, ma potresti essere in grado di trovare implementazioni alternative di threadpool adatte.

anche

  

new Thread (). Start ()

genera thread in primo piano che non moriranno se chiudi il programma. I thread di ThreadPool sono thread in background che muoiono quando chiudi l'app.

Ero curioso dell'utilizzo delle risorse relative per questi e ho eseguito un benchmark sul mio laptop Intel i5 dual-core 2012 utilizzando la versione .net 4.0 build su Windows 8. I pool di thread hanno impiegato in media 0,035 ms per iniziare dove i thread hanno preso un media di 5,06 ms. In altre parole, Thread nel pool è stato avviato circa 300 volte più veloce per un numero elevato di thread di breve durata. Almeno nell'intervallo testato (100-2000) thread, il tempo totale per thread sembrava piuttosto costante.

Questo è il codice che è stato confrontato:

    for (int i = 0; i < ThreadCount; i++) {
        Task.Run(() => { });
    }

    for (int i = 0; i < ThreadCount; i++) {
        var t = new Thread(() => { });
        t.Start();
    }

 inserisci qui la descrizione dell'immagine

Controlla qui per una discussione precedente:

Quando non dovrei usare ThreadPool in .Net?

Riepilogo è che Threadpool è utile se devi generare molti thread di breve durata, mentre l'utilizzo di Thread ti dà un po 'più di controllo.

L'archiviazione locale dei thread non è una buona idea con i pool di thread. Dà alle discussioni un '"identità"; non tutti i thread sono più uguali. Ora i pool di thread sono particolarmente utili se hai solo bisogno di un gruppo di thread identici, pronti a fare il tuo lavoro senza sovraccarico di creazione.

Se hai bisogno di molti thread, probabilmente vuoi usare un ThreadPool. Riutilizzano i thread risparmiando il sovraccarico della creazione del thread.

Se hai solo bisogno di un thread per fare qualcosa, Thread è probabilmente il più semplice.

L'esigenza principale dei thread dello stagno è quella di gestire brevi attività che dovrebbero essere completate quasi all'istante. I gestori di interrupt di processo vengono spesso eseguiti in un contesto di stacking che non sarebbe adatto per il codice non kernel, ma un gestore di interrupt di processo potrebbe scoprire che un callback di completamento I / O in modalità utente deve essere eseguito il prima possibile. Creare un nuovo thread allo scopo di eseguire una cosa del genere sarebbe eccessivo. Avere alcuni thread pre-creati che possono essere inviati per eseguire callback di completamento I / O o altre cose simili è molto più efficiente.

Un aspetto chiave di tali thread è che se i metodi di completamento dell'I / O si completano sempre essenzialmente istantaneamente e non si bloccano mai, e il numero di tali thread che attualmente eseguono tali metodi è almeno uguale al numero di processori, l'unico modo qualsiasi altro thread potrebbe essere eseguito prima che uno dei metodi sopra menzionati finisca se uno degli altri metodi si blocchi o il suo tempo di esecuzione supera un normale intervallo di threading; nessuno di questi dovrebbe accadere molto spesso se il pool di thread viene utilizzato come previsto.

Se non ci si può aspettare che un metodo esca entro 100 ms o più da quando inizia l'esecuzione, il metodo dovrebbe essere eseguito in qualche modo diverso dal pool di thread principale. Se uno ha molte attività da svolgere che richiedono molta CPU ma non si bloccheranno, può essere utile inviarle utilizzando un pool di thread dell'applicazione (uno per core della CPU) che è separato da "main" threadpool, poiché l'utilizzo di più thread rispetto ai core sarà controproducente quando si eseguono attività ad alta intensità di CPU non bloccanti. Se, tuttavia, un metodo impiegherà un secondo o più per essere eseguito e trascorrerà la maggior parte del suo tempo bloccato, il metodo dovrebbe probabilmente essere eseguito in un thread dedicato e quasi sicuramente non dovrebbe essere eseguito in un thread main-threadpool. Se un'operazione di lunga durata deve essere innescata da qualcosa come un callback I / O, si dovrebbe o avviare un thread per l'operazione di lunga durata prima del callback e farlo attendere su un monitor che pulsa il callback, oppure fare in modo che il callback avvii un nuovo thread per eseguire l'operazione mentre il callback esce, restituendo effettivamente il proprio thread al threadpool.

In generale (non ho mai usato .NET), un pool di thread verrebbe utilizzato per scopi di gestione delle risorse. Consente di configurare i vincoli nel software. Potrebbe anche essere fatto per motivi di prestazioni, poiché la creazione di nuovi thread potrebbe essere costosa.

Potrebbero esserci anche motivi specifici del sistema. In Java (di nuovo non so se questo si applica a .NET), il gestore dei thread può applicare variabili specifiche del thread mentre ogni thread viene estratto dal pool e disinserirli quando vengono restituiti (modo comune per passare qualcosa come un'identità).

Esempio di vincolo: Ho solo 10 connessioni db, quindi consentirei solo 10 thread di lavoro per accedere al database.

Questo non significa che non dovresti creare i tuoi thread, ma ci sono condizioni in cui ha senso usare un pool.

L'uso di un pool è una buona idea, se non si conosce o non si può controllare il numero di thread che verranno creati.

Basta avere un problema con un modulo che usa il thread per aggiornare un campo da un database su un evento con cambio di posizione di un controllo di lista (evitare freez). Il mio utente ha impiegato 5 minuti per avere un errore dal database (troppe connessioni con Access) perché stava cambiando la posizione dell'elenco troppo velocemente ...

So che esiste un altro modo per risolvere il problema di base (incluso il non utilizzo dell'accesso) ma il pooling è un buon inizio.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top