Domanda

Sto scrivendo un server e ramo ogni azione in un thread quando la richiesta è in arrivo.Lo faccio perché quasi ogni richiesta effettua query sul database.Sto utilizzando una libreria threadpool per ridurre la costruzione/distruzione dei thread.

La mia domanda è però: qual è un buon punto di interruzione per thread I/O come questi?So che sarebbe solo una stima approssimativa, ma stiamo parlando di centinaia?migliaia?


MODIFICARE:

Grazie a tutti per le vostre risposte, sembra che dovrò testarlo per scoprire il mio limite massimo di thread.La domanda è però:come faccio a sapere di aver raggiunto quel limite?Cosa dovrei misurare esattamente?

È stato utile?

Soluzione

Alcuni direbbero che due sono troppi - non sono proprio in quel campo :-)

Ecco il mio consiglio: misura, non indovinare. Un suggerimento è di renderlo configurabile e inizialmente impostarlo su 100, quindi rilasciare il tuo software allo stato brado e monitorare cosa succede.

Se l'utilizzo del thread raggiunge il picco a 3, 100 è troppo. Se rimane a 100 per la maggior parte della giornata, aumentalo fino a 200 e vedi cosa succede.

Tu potresti effettivamente che il tuo codice stesso controlli l'utilizzo e aggiusti la configurazione per il prossimo avvio ma probabilmente è eccessivo.


Per chiarimenti ed elaborazione:

Non sto proponendo di far rotolare il tuo sottosistema di pool di thread, usa sicuramente quello che hai. Ma, dal momento che stavi chiedendo un buon punto di interruzione per i thread, suppongo che l'implementazione del pool di thread abbia la capacità di limitare il numero massimo di thread creati (il che è una buona cosa).

Ho scritto il codice di pooling delle connessioni di thread e database e hanno le seguenti funzionalità (che credo siano essenziali per le prestazioni):

  • un numero minimo di thread attivi.
  • un numero massimo di thread.
  • chiusura di thread non utilizzati da un po 'di tempo.

Il primo imposta una base per le prestazioni minime in termini di client del pool di thread (questo numero di thread è sempre disponibile per l'uso). Il secondo imposta una restrizione sull'utilizzo delle risorse da parte dei thread attivi. Il terzo ti riporta alla baseline in tempi tranquilli in modo da ridurre al minimo l'uso delle risorse.

È necessario bilanciare l'utilizzo delle risorse di thread non utilizzati (A) rispetto all'utilizzo delle risorse di non disporre di thread sufficienti per eseguire il lavoro (B).

(A) è generalmente l'utilizzo della memoria (stack e così via) poiché un thread che non fa alcun lavoro non utilizzerà gran parte della CPU. (B) genererà generalmente un ritardo nell'elaborazione delle richieste quando arrivano poiché è necessario attendere che una discussione diventi disponibile.

Ecco perché misuri. Come dici, la stragrande maggioranza dei tuoi thread aspetterà una risposta dal database in modo che non siano in esecuzione. Ci sono due fattori che influenzano il numero di thread che dovresti consentire.

Il primo è il numero di connessioni DB disponibili. Questo potrebbe essere un limite rigido a meno che tu non possa aumentarlo nel DBMS - suppongo che il tuo DBMS possa prendere un numero illimitato di connessioni in questo caso (anche se idealmente dovresti anche misurarlo).

Quindi, il numero di thread che dovresti avere dipende dal tuo uso storico. Il minimo che dovresti avere è il numero minimo che tu abbia mai avuto in esecuzione + A%, con un minimo assoluto di (ad esempio, e rendilo configurabile proprio come A) 5.

Il numero massimo di thread deve essere il massimo storico + B%.

Dovresti anche monitorare i cambiamenti di comportamento. Se, per qualche motivo, l'utilizzo va al 100% di quello disponibile per un tempo significativo (in modo da influire sulle prestazioni dei clienti), è necessario aumentare il massimo consentito fino a quando non sarà di nuovo superiore del B%.


In risposta alla quot &, cosa devo misurare esattamente? " domanda:

Quello che dovresti misurare specificamente è la quantità massima di thread in uso simultaneo (ad esempio, in attesa di un ritorno dalla chiamata DB) sotto carico. Quindi aggiungi un fattore di sicurezza del 10% per esempio (sottolineato, poiché altri poster sembrano prendere i miei esempi come raccomandazioni fisse).

Inoltre, ciò dovrebbe essere fatto nell'ambiente di produzione per l'ottimizzazione. Va bene ottenere un preventivo in anticipo, ma non si sa mai quale produzione si farà strada (motivo per cui tutte queste cose dovrebbero essere configurabili in fase di esecuzione). Questo per cogliere una situazione come il raddoppio imprevisto delle chiamate dei clienti in arrivo.

Altri suggerimenti

Questa domanda è stata discussa abbastanza approfonditamente e non ho avuto la possibilità di leggere tutte le risposte. Ma ecco alcune cose da prendere in considerazione osservando il limite superiore del numero di thread simultanei che possono coesistere pacificamente in un determinato sistema.

  1. Dimensione stack thread: in Linux la dimensione stack stack predefinita è 8 MB (è possibile utilizzare ulimit -a per scoprirlo).
  2. Max memoria virtuale supportata da una determinata variante del sistema operativo. Linux Kernel 2.4 supporta uno spazio di indirizzi di memoria di 2 GB. con Kernel 2.6, sono un po 'più grande (3 GB)
  3. [1] mostra i calcoli per il numero massimo di thread per una determinata VM massima supportata. Per 2.4 risulta essere di circa 255 thread. per 2.6 il numero è un po 'più grande.
  4. Che tipo di scheduler del kernel hai. Confrontando lo scheduler del kernel Linux 2.4 con 2.6, il successivo ti dà una pianificazione O (1) senza dipendenza dal numero di compiti esistenti in un sistema mentre il primo è più di un O (n). Quindi anche le capacità SMP del programma del kernel svolgono un buon ruolo nel numero massimo di thread sostenibili in un sistema.

Ora puoi ottimizzare le dimensioni dello stack per incorporare più thread, ma poi devi tenere conto delle spese generali di gestione dei thread (creazione / distruzione e pianificazione). È possibile applicare l'affinità della CPU a un determinato processo, nonché a un determinato thread per legarli a CPU specifiche per evitare sovraccarichi di migrazione dei thread tra le CPU ed evitare problemi di liquidità.

Si noti che si possono creare migliaia di thread a suo piacimento, ma quando Linux si esaurisce la VM, inizia casualmente a uccidere i processi (quindi i thread). Questo per evitare che il profilo di utilità venga massimizzato. (La funzione utility indica l'utilità a livello di sistema per una determinata quantità di risorse. Con risorse costanti in questo caso Cicli e memoria della CPU, la curva dell'utilità si appiattisce con un numero sempre maggiore di attività).

Sono sicuro che anche lo scheduler del kernel di Windows fa qualcosa del genere per gestire un utilizzo eccessivo delle risorse

[1] http://adywicaksono.wordpress.com/2007/07/10/i-can-not-create-more-than-255-threads-on-linux-what-is-the-solutions/

Se i tuoi thread eseguono qualsiasi tipo di lavoro ad alta intensità di risorse (CPU/disco), raramente vedrai vantaggi oltre uno o due e troppi uccideranno le prestazioni molto rapidamente.

Il "caso migliore" è che i thread successivi si bloccheranno mentre i primi vengono completati, o alcuni avranno blocchi a basso costo sulle risorse con bassa contesa.Il caso peggiore è che inizi a impegnare cache/disco/rete e il throughput complessivo diminuisce.

Una buona soluzione è inserire richieste in un pool che vengono poi inviate ai thread di lavoro da un pool di thread (e sì, evitare la creazione/distruzione continua di thread è un ottimo primo passo).

Il numero di thread attivi in ​​questo pool può quindi essere modificato e ridimensionato in base ai risultati della profilazione, all'hardware su cui si sta eseguendo e ad altre cose che potrebbero verificarsi sulla macchina.

Una cosa da tenere a mente è che Python (almeno la versione basata su C) utilizza ciò che viene chiamato blocco dell'interprete globale che può avere un impatto enorme sulle prestazioni su macchine multi-core.

Se hai davvero bisogno del massimo da Python multithread, potresti prendere in considerazione l'uso di Jython o qualcosa del genere.

Come giustamente affermato da Pax, misura, non indovinare . Quello che ho fatto per DNSwitness e i risultati sono stati sorprendenti: il numero ideale di thread era molto più alto di quanto pensassi, qualcosa come 15.000 thread per ottenere i risultati più veloci.

Certo, dipende da molte cose, ecco perché devi misurarti.

Misure complete (solo in francese) in Combien de fils d'ex & # 233; attenzione? .

Ho scritto diverse app multi-thread. In genere, consento al numero di potenziali thread di essere specificato da un file di configurazione. Quando mi sono sintonizzato per clienti specifici, ho impostato il numero abbastanza alto che il mio utilizzo di tutti i core della CPU era piuttosto alto, ma non così alto da incorrere in problemi di memoria (questi erano sistemi operativi a 32 bit sul tempo).

In altre parole, una volta raggiunti alcuni colli di bottiglia che si tratti di CPU, throughput del database, throughput del disco, ecc., l'aggiunta di più thread non aumenta le prestazioni complessive. Ma fino a quando non raggiungi quel punto, aggiungi più discussioni!

Tieni presente che ciò presuppone che i sistemi in questione siano dedicati alla tua app e che tu non debba giocare bene (evitare di morire di fame) altre app.

Il " big iron " la risposta è generalmente un thread per risorsa limitata - processore (limite CPU), arm (limite I / O), ecc. - ma funziona solo se è possibile instradare il lavoro al thread corretto per l'accesso alla risorsa.

Laddove ciò non sia possibile, considera che hai risorse fungibili (CPU) e risorse non fungibili (armi). Per le CPU non è fondamentale assegnare ogni thread a una CPU specifica (anche se aiuta con la gestione della cache), ma per i bracci, se non è possibile assegnare un thread al braccio, si entra nella teoria dell'accodamento e qual è il numero ottimale per mantenere i bracci occupato. In generale sto pensando che se non puoi instradare le richieste in base al braccio utilizzato, allora avere 2-3 thread per braccio sarà corretto.

Una complicazione si presenta quando l'unità di lavoro passata al thread non esegue un'unità di lavoro ragionevolmente atomica. Ad esempio, potresti avere il thread ad un certo punto accedere al disco, ad un altro punto attendere su una rete. Ciò aumenta il numero di & Quot; crack & Quot; dove ulteriori thread possono entrare e fare un lavoro utile, ma aumenta anche l'opportunità che thread aggiuntivi si inquinino a vicenda cache, ecc. e impantanano il sistema.

Ovviamente, devi valutare tutto questo rispetto al " peso " di una discussione. Sfortunatamente, la maggior parte dei sistemi ha thread molto pesanti (e ciò che chiamano & Quot; thread leggeri & Quot; spesso non sono affatto thread), quindi è meglio sbagliare sul lato basso.

Quello che ho visto in pratica è che differenze molto sottili possono fare un'enorme differenza nel numero di thread ottimali. In particolare, problemi di cache e conflitti di blocco possono limitare notevolmente la quantità di concorrenza pratica.

Una cosa da considerare è il numero di core presenti sulla macchina che eseguirà il codice. Ciò rappresenta un limite per il numero di thread che possono procedere in un determinato momento. Tuttavia, se, come nel tuo caso, si prevede che i thread attenderanno frequentemente l'esecuzione di una query da parte di un database, probabilmente vorrai ottimizzare i thread in base al numero di query simultanee che il database può elaborare.

Penso che questo sia un po 'una schivata alla tua domanda, ma perché non inserirli in processi? La mia comprensione del networking (dai tempi nebbiosi di un tempo, in realtà non codifico affatto le reti) era che ogni connessione in entrata può essere gestita come un processo separato, perché quindi se qualcuno fa qualcosa di brutto nel tuo processo, non lo fa nuke l'intero programma.

ryeguy, attualmente sto sviluppando un'applicazione simile e il mio numero di thread è impostato su 15. Sfortunatamente se lo aumento a 20, si blocca. Quindi, sì, penso che il modo migliore per gestirlo sia misurare se la tua configurazione attuale consente più o meno di un numero X di thread.

Nella maggior parte dei casi dovresti consentire al pool di thread di gestirlo. Se pubblichi un codice o fornisci ulteriori dettagli, potrebbe essere più facile vedere se c'è qualche motivo per cui il comportamento predefinito del pool di thread non sarebbe ottimale.

Puoi trovare ulteriori informazioni su come dovrebbe funzionare qui: http://en.wikipedia.org / wiki / Thread_pool_pattern

Quanti thread quanti sono i core della CPU sono quelli che ho sentito molto spesso.

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