Queue vs Threads

4

Sto implementando un software di elaborazione dati. Il software ottiene dalla rete migliaia di eventi che devono essere elaborati secondo le regole. Ho implementato un servizio multi-thread, che riceve l'evento e lo inserisce nel motore di elaborazione.

Questo significa che ogni evento in entrata crea una nuova attività eseguibile e restituisce il controllo al thread principale. Il thread secondario inserisce i dati e muore, che è solo alcuni secondi.

Questa metodologia crea molti thread (da 150 a 260), e ho ricevuto "lamentele" che questo non è il modo giusto per farlo. Dovrei quindi limitare i thread a 5 o 10. Per me il modo in cui ho implementato è il solito modo. Quindi le mie domande sono:

  1. Devo limitare i thread?

  2. C'è un "modo giusto" stabilito per fare questo genere di cose?

Nota: i thread attualmente vengono creati in un pool di thread Java: java.util.concurrent.ThreadPoolExecutor .

    
posta ender.an27 09.03.2016 - 13:04
fonte

3 risposte

6

La creazione e la gestione dei thread è in realtà un'operazione piuttosto costosa. La creazione di più thread rispetto ai core CPU è solitamente controproducente a causa del sovraccarico di gestione dei thread. Ancora più difficile quando i tuoi thread sono di breve durata, il che significa che vengono creati e distrutti continuamente dal sistema operativo.

Un approccio migliore per la parallelizzazione di un gran numero di piccole attività consiste nel creare un numero fisso di thread una volta e quindi elaborare la coda assegnando una nuova attività a ciascun thread al termine dell'ultima. Sembra che sia difficile da implementare, ma farlo con Java è in realtà molto semplice perché esiste già una classe per questo:

java.util.concurrent.ThreadPoolExecutor

È accetta le attività sotto forma di oggetti che implementano Runnable . Questa è un'interfaccia funzionale, quindi con Java 8 puoi semplicemente passare una chiamata al metodo.

La dimensione del pool di thread deve essere scelta in modo da non creare più thread di quanti ne possiedi. Un buon modo per farlo è utilizzare Executors.newFixedThreadPool metodo di supporto in combinazione con Runtime.availableProcessors() :

Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() - 1)

Il - 1 è perché hai bisogno di un core CPU aggiuntivo per il thread principale del tuo programma.

    
risposta data 09.03.2016 - 14:06
fonte
2

Creare un numero di thread pari agli eventi in ingresso è generalmente una cattiva idea se il numero di eventi è "grande". 150 thread non è così problematico, ma immagina di ricevere eventi sempre più frequentemente ... Non puoi occupartene indefinitamente. Quindi, il fatto che tu abbia 150 thread è una prova che c'è qualcosa che potrebbe diventare sbagliato.

Dai un'occhiata alla classe ThreadPoolExecutor , potrebbe essere quello che stai cercando. Fondamentalmente, crea un pool di thread (è possibile utilizzare un pool di dimensioni fisse di 5 thread per esempio) e prende una coda di blocco.

Quando ricevi un nuovo evento, inseriscilo nella coda di blocco (che può avere una dimensione limitata, in modo che non sia possibile riempire tutta la memoria con gli eventi; sono disponibili diverse norme di sovraccarico)

Ciascuno dei tuoi thread dal pool specificato chiederà continuamente alla coda un nuovo evento. Se un tale evento è in coda, la coda lo recupera nel thread, che può iniziare il suo lavoro. Se la coda è vuota, la chiamata verrà bloccata. Quindi, in pratica, ogni thread richiede solo un evento e "attende" fino a quando un evento non entra in coda.

Modifica : sono stato lasciato indietro da @Philipp, mi dispiace per quello.

Si noti inoltre che, dal momento che Java 7, la classe ForkJoinPool è in grado di eseguire thread che non sono bloccati, in questo modo si hanno realmente N thread attivi in qualsiasi momento. Quindi indovinare il numero effettivo di thread viventi (inclusi quelli bloccati) diventa un gioco difficile.

    
risposta data 09.03.2016 - 14:16
fonte
0

No, sembra un modo abbastanza rischioso per farlo.

L'inserimento in una coda è un'operazione molto veloce (presupponendo che la coda sia in memoria o sulla macchina). La creazione di un thread o anche il prelievo di uno da un pool richiederà più tempo. Se stai utilizzando una coda di messaggi comune su un altro computer, potrebbe avere o meno senso.

Il modo migliore per saperlo è testarlo. Crea una versione che utilizza thread e uno che non li fa e mettili sotto carico. Come cambia il tasso di risposta mentre aggiungi il carico? Quando il sistema inizia a fallire? Incontri bug di concorrenza?

    
risposta data 09.03.2016 - 13:20
fonte

Leggi altre domande sui tag