Impostazione della dimensione ideale del pool di thread

Qual è la differenza tra-

newSingleThreadExecutor vs newFixedThreadPool(20)

in termini di sistema operativo e punto di vista della programmazione.

Ogni volta che newSingleThreadExecutor mio programma usando newSingleThreadExecutor mio programma funziona molto bene e la latenza end-to-end (95 ° percentile) arriva a circa 5 5ms .

Ma non appena inizio a gestire il mio programma usando-

newFixedThreadPool(20)

le mie prestazioni del programma peggiorano e comincio a vedere una latenza end-to-end di 37ms .

Quindi ora sto cercando di capire dal punto di vista dell’architettura cosa significa qui il numero di thread? E come decidere qual è il numero ottimale di discussioni che dovrei scegliere?

E se sto usando un numero maggiore di thread, allora cosa succederà?

Se qualcuno mi può spiegare queste semplici cose in un linguaggio laico, allora mi sarà molto utile. Grazie per l’aiuto.

La mia configurazione macchina specifica – Sto facendo girare il mio programma dalla macchina Linux-

 processor : 0 vendor_id : GenuineIntel cpu family : 6 model : 45 model name : Intel(R) Xeon(R) CPU E5-2670 0 @ 2.60GHz stepping : 7 cpu MHz : 2599.999 cache size : 20480 KB fpu : yes fpu_exception : yes cpuid level : 13 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss syscall nx rdtscp lm constant_tsc arch_perfmon pebs bts rep_good xtopology tsc_reliable nonstop_tsc aperfmperf pni pclmulqdq ssse3 cx16 sse4_1 sse4_2 popcnt aes hypervisor lahf_lm arat pln pts bogomips : 5199.99 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual power management: processor : 1 vendor_id : GenuineIntel cpu family : 6 model : 45 model name : Intel(R) Xeon(R) CPU E5-2670 0 @ 2.60GHz stepping : 7 cpu MHz : 2599.999 cache size : 20480 KB fpu : yes fpu_exception : yes cpuid level : 13 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss syscall nx rdtscp lm constant_tsc arch_perfmon pebs bts rep_good xtopology tsc_reliable nonstop_tsc aperfmperf pni pclmulqdq ssse3 cx16 sse4_1 sse4_2 popcnt aes hypervisor lahf_lm arat pln pts bogomips : 5199.99 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual power management: 

Ok. Idealmente supponendo che i thread non abbiano un blocco tale da non bloccarsi l’un l’altro (indipendentemente l’uno dall’altro) e si può presumere che il carico di lavoro (elaborazione) sia lo stesso, quindi si scopre che hanno una dimensione del pool di Runtime.getRuntime().availableProcessors() o availableProcessors() + 1 dà i risultati migliori.

Ma diciamo che se i fili interferiscono tra loro o se l’I / O è coinvolto, allora la legge di Amadhal spiega piuttosto bene. Da wiki,

La legge di Amdahl afferma che se P è la proporzione di un programma che può essere reso parallelo (cioè, beneficio dalla parallelizzazione), e (1 – P) è la proporzione che non può essere parallelizzata (rimane seriale), quindi la massima velocità che può essere raggiunto utilizzando N processori è

Legge di Amadhal

Nel tuo caso, in base al numero di core disponibili e al lavoro che fanno esattamente (calcolo puro? I / O? Tenere blocchi? Bloccato per qualche risorsa? Ecc.), Devi trovare la soluzione basata sopra parametri.

Ad esempio: alcuni mesi fa ero coinvolto nella raccolta di dati da siti web numerali. La mia macchina era a 4 core e avevo una dimensione di piscina di 4 . Ma poiché l’operazione era puramente I/O e la mia velocità di rete era decente, mi sono reso conto che avevo le migliori prestazioni con una piscina di 7 . E questo perché i thread non combattevano per il potere computazionale, ma per I / O. Quindi ho potuto sfruttare il fatto che più thread possono contestare positivamente il core.

PS: Suggerisco, passando attraverso il capitolo Performance dal libro – Java Concurrency in Practice di Brian Goetz. Si occupa di tali argomenti in dettaglio.

Quindi ora sto cercando di capire dal punto di vista dell’architettura cosa significa qui il numero di thread?

Ogni thread ha una propria memoria di stack, un contatore di programmi (come un puntatore a ciò che viene eseguito successivamente) e altre risorse locali. Scambiarli fa male la latenza per una singola attività. Il vantaggio è che mentre un thread è inattivo (di solito quando si attende I / o), un altro thread può funzionare. Inoltre, se sono disponibili più processori, possono essere eseguiti in parallelo se non vi sono conflitti di risorse e / o di blocco tra le attività.

E come decidere qual è il numero ottimale di discussioni che dovrei scegliere?

Il compromesso tra prezzo swap e opportunità per evitare tempi morti dipende dai piccoli dettagli di ciò che il tuo compito assomiglia (quanto I / O, e quando, con quanto lavoro tra I / O, usando quanta memoria a completare). La sperimentazione è sempre la chiave.

E se sto usando un numero maggiore di thread, allora cosa succederà?

Di solito ci sarà una crescita lineare della produttività, quindi una relativa parte piatta, quindi una goccia (che potrebbe essere piuttosto ripida). Ogni sistema è diverso.

Osservare la legge di Amdahl va bene, specialmente se sai esattamente quanto sono grandi le P e N. Dal momento che ciò non accadrà mai, è ansible monitorare le prestazioni (cosa che si dovrebbe fare comunque) e aumentare / ridurre la dimensione del pool di thread per ottimizzare le metriche relative al rendimento che sono importanti per l’utente.