I thread usano la memoria virtuale o la memoria reale?


10

Stavo cercando di ottimizzare il mio server Linux per gestire 10.000 thread per processo mentre ora fa solo 382. Come da questo articolo viene utilizzata la seguente formula per scoprire i thread possibili totali:

number of threads = total virtual memory / (stack size*1024*1024)

Ciò significa che i thread archiviano tutti i loro dati nella memoria virtuale. E per quanto ne so, la memoria virtuale è lo spazio di swap in una macchina Linux che è memorizzata su hard disk di RAM o cache.

Quindi la mia domanda è se i nostri thread usano l'hard disk per archiviare per elaborare / archiviare i suoi dati.

Se sì, allora questo effetto non ha effetto? Possiamo migliorare le prestazioni inserendole nella RAM o nella cache? Come?

In caso negativo, come funzionano esattamente i thread?

Aggiornare:

Secondo la risposta inutile , la memoria virtuale è un sistema che comprende all'incirca:

  • memoria fisica (RAM)
  • eventuali file di scambio che hai allegato
  • supporto hardware per la traduzione di indirizzi da virtuali a fisici e l'emissione di errori di pagina quando un indirizzo virtuale non è disponibile nella memoria fisica
  • (kernel) supporto software per: gestire le tabelle di ricerca utilizzate da quell'hardware gestendo quegli errori di pagina estraendo le pagine dallo scambio su richiesta

Pertanto, tutto ciò che è nella memoria virtuale è collettivamente su RAM (memoria reale) e disco rigido (file di scambio). E come James spiega nella sua risposta, la decisione su Ram vs HDD viene presa da Kernel usando algoritmi come LRU.


2
a meno che il tuo server non abbia 10.000 CPU / core, stai perdendo tempo.

@JarrodRoberson: Qual è il motivo per cui?
dragosrsupercool,

3
10.000 thread non sono un buon modo per ridimensionare le cose, è un buon modo per fare in modo che un server entri in una ricerca per indicizzazione, più di 1 thread per CPU o Core farà semplicemente cambiare il contesto del server ed eseguire più lentamente, non più velocemente.

In particolare, quando dici "cercando di ottimizzare il mio server Linux" - cosa stai cercando di ottimizzare? Se è throughput, è probabile che sia meglio un thread per CPU con I / O multiplexing e non bloccante.
Inutile

Risposte:


12

per quanto ne so, la memoria virtuale è lo spazio di swap in una macchina Linux

No, la memoria virtuale è un sistema che comprende all'incirca:

  • memoria fisica (RAM)
  • eventuali file di scambio che hai allegato
  • supporto hardware per la traduzione di indirizzi da virtuali a fisici e l'emissione di errori di pagina quando un indirizzo virtuale non è disponibile nella memoria fisica
  • (kernel) supporto software per:
    • gestione delle tabelle di ricerca utilizzate da tale hardware
    • gestire tali errori di pagina estraendo le pagine dallo scambio su richiesta

Spetta al kernel assicurarsi che la memoria virtuale desiderata sia memorizzata nella cache nella RAM quando lo si desidera, a meno che non si stia scrivendo il proprio livello VM dello spazio utente (come spesso accade ai database, iiuc), non preoccuparsene.


Ok, quindi il mio presupposto di memoria virtuale era sbagliato. In ogni caso, una domanda di follow-up rapido. Le prestazioni dei thread max caricati completamente sarebbero influenzate se SWAP Space fosse superiore alla RAM?
dragosrsupercool,

@dragosrsupercool: lo spazio di scambio sarà sempre più grande della memoria fisica, altrimenti è necessario utilizzare la memoria virtuale.
Bryan Oakley,

1
@BryanOakley: non è necessariamente vero. Alcuni SO assegnano una pagina di swap per ogni pagina virtuale allocata (cioè lo swap deve essere almeno grande quanto fisico). Altri sistemi operativi allocano una pagina di scambio solo quando è necessario spostare una pagina dalla memoria fisica (cioè lo scambio può essere inferiore a quello fisico). Il vantaggio del primo è che se l'allocazione ha esito positivo, la sostituzione della memoria ha sempre successo. Il vantaggio di quest'ultimo è che non è necessario allocare pessimisticamente enormi file di scambio per tenere conto di situazioni relativamente rare.
mcmcc,

1
@dragosrsupercool, le prestazioni non saranno influenzate dalla quantità di RAM, dallo scambio o dal rapporto tra loro a meno che tu non abbia poca RAM e effettivamente il paging. sar può parlarti dell'attività di paging iirc (selezionata: sar -Bsu Linux).
Inutile

@Useless: desidero aumentare il numero di thread fino a quando non utilizzo completamente la RAM e non inizio il paging.
dragosrsupercool,

14

Se il thread è effettivamente in esecuzione, l'istruzione corrente e tutte le variabili utilizzate dal thread devono essere nella memoria fisica.

La maggior parte (in effetti quasi tutti) i programmi risiedono nella memoria virtuale e la maggior parte dei programmi utilizza la memoria virtuale per l'archiviazione delle variabili.

Indirizzi virtuali organizzati in blocchi chiamati pagine (generalmente blocchi da 4096 o 8192 byte).

In qualsiasi momento, ogni blocco di memoria virtuale viene archiviato da qualche parte nella memoria reale o sul disco nello "spazio di scambio" riservato a questo.

Il codice del tuo programma si occupa di indirizzi virtuali, quando ti ramifichi a un indirizzo virtuale o richiedi l'accesso alla memoria a un indirizzo virtuale in cui il sistema (di solito a livello hardware) individua la posizione corrente della richiesta di indirizzo e la mappa al tuo indirizzo virtuale, se l'indirizzo attualmente risiede sul disco, lo inserisce nella memoria reale e quindi mappa l'indirizzo.

Ovviamente quando tutta la memoria fisica è in uso se è stato effettuato il paging di qualcos'altro, allora qualcos'altro deve essere sfogliato, quindi il sistema cerca la pagina "Meno usato di recente" e copia questa su disco prima di copiare la pagina richiesta.

Nei sistemi moderni ci sono diverse ottimizzazioni e trucchi associati all'archiviazione virtuale.

  • Gli indirizzi sono mappati su una base "per processo", quindi ad esempio tutti i programmi C in una scatola Linux avviano il processo "principale" allo stesso indirizzo.
  • Ciò può consentire a diversi processi a 32 bit di occupare e utilizzare molto più di 4 GB su una macchina poiché un indirizzo virtuale a 32 bit può essere mappato su un indirizzo reale a 64 bit.
  • Quando i processi terminano o la memoria è altrimenti "libera", il sistema contrassegna semplicemente le pagine come libere, non vengono mai copiate sul disco di scambio.
  • Allo stesso modo, quando viene richiesto un nuovo blocco di memoria, il sistema acquisisce solo una pagina libera nella memoria reale, no, l'IO del disco ha luogo.
  • Le funzioni di sospensione e ibernazione costringono tutta la memoria a essere copiata nello spazio di scambio in modo che tutti i processi correnti e i contenuti della memoria corrente possano essere ricreati al risveglio.

3
I "tutti i programmi C in un box Linux iniziano [main] allo stesso indirizzo" non sembrano prendere in considerazione la randomizzazione del layout dello spazio degli indirizzi. Oggi è usato sempre più spesso per contrastare vari schemi di attacco che distruggono lo stack. Buona risposta altrimenti, quindi +1.
un CVn del

7

Prima di tutto, devi leggere di più sulla memoria del computer , perché sembra che manchi la conoscenza in quel campo.

Un thread di esecuzione è la più piccola unità di elaborazione che può essere programmata da un sistema operativo. L'implementazione di thread e processi differisce da un sistema operativo all'altro, ma nella maggior parte dei casi un thread è contenuto all'interno di un processo. Più thread possono esistere all'interno dello stesso processo e condividere risorse come la memoria, mentre processi diversi non condividono queste risorse.

Quindi, i thread useranno la memoria disponibile, qualunque sia il tipo di memoria disponibile. Il numero di thread che è possibile avviare dipende dalla dimensione della memoria e dalla quantità di memoria necessaria per thread. Se il thread utilizza heap (non solo stack), ha bisogno di più memoria e in tal caso puoi avviare meno thread.


@VJonvic: +1 per la spiegazione di base del thread.
dragosrsupercool,

6

La semplice risposta alla tua domanda è che usano la memoria virtuale. tutto usa la memoria virtuale tranne una manciata di processi relativi al sistema operativo.

D'altra parte, quando il thread (o qualsiasi thread, in qualsiasi processo) è effettivamente in esecuzione, utilizza la memoria fisica. Le pagine di memoria associate a quel processo vengono scambiate con la memoria fisica che è dove il processore fa il suo lavoro.


3

La memoria virtuale è la tua RAM più il tuo spazio di swap. Virtuale significa solo che l'indirizzo visualizzato dal tuo programma è diverso dall'indirizzo visualizzato dal chip RAM. Se è necessario accedere alla memoria tramite swap, il sistema operativo la sposterà prima nella RAM. Se non vuoi scambiare, disabilitalo. Se hai abbastanza RAM non ne hai davvero bisogno.

Detto questo, a meno che tu non abbia un processore da 10.000 core, aumentare a 10.000 thread non è in realtà una "ottimizzazione". Una volta che hai abbastanza thread per consumare tutti i core, oltre a uno o due pezzi di ricambio per quando quei thread sono bloccati, l'aggiunta di più thread riduce le prestazioni a causa dell'overhead di commutazione e dei mancati cache. Potresti comunque voler usare più thread se questo semplifica la logica del tuo programma, ma comprometterai le prestazioni.


Sì, 10.000 è troppo perché il mio server è una macchina single core a 32 bit. In realtà, i thread non sono cosa totale della CPU. Sono thread del crawler, quindi a volte sarebbe come aspettare la risposta del server. Mi propongo di assicurarmi che la CPU sia totalmente occupata ma non sovraccaricata o sottocarica. Ma non riesco ancora a capire come posso sapere se la CPU è come libera o totalmente occupata. C'è qualche strumento o comando?
dragosrsupercool,

Penso che tu possa ottenere quelle informazioni dal topcomando.
Karl Bielefeldt,

@KarlBieledeldt: sì, era esattamente quello che stavo cercando. Un'altra domanda di follow-up: ho appena avuto un'idea per la ricerca per indicizzazione che se un thread può inviare una richiesta di URL mentre l'altro thread riceve la risposta del server, allora posso continuare Utilizzo elevato della CPU senza utilizzare troppi thread. È possibile? Come inviare una richiesta da un thread mentre si riceve la risposta sull'altro thread?
dragosrsupercool,

2

ottimizzare il mio server Linux per gestire 10.000 thread per processo

Come altri hanno spiegato, questo è generalmente sbagliato. Un thread è una risorsa costosa , in particolare perché ha il proprio stack di chiamate (in genere un megabyte) e perché è un'attività programmabile dal kernel. I thread sono ancora più costosi dei descrittori di file aperti .

Leggi i sistemi operativi: tre pezzi facili (libro di testo scaricabile gratuitamente).

Come regola generale, non si desidera avere molti thread e certamente non molti thread eseguibili. Il numero di thread eseguibili dovrebbe generalmente essere al massimo il numero di core (o un piccolo multiplo di quello), quindi circa una dozzina al massimo. Il numero di thread in un processo potrebbe essere leggermente più grande. Quindi, a meno che tu non abbia un server molto espansivo (con molti socket e core del processore), non vuoi avere più di una dozzina di thread eseguibili e un centinaio di thread (molti dei quali sono inattivi) nel tuo processo (sul desktop) .

Su Linux, thread e processi sono molto simili (poiché entrambi possono essere creati da clone (2) ) ed entrambi sono attività pianificate dal kernel. In realtà lo scheduler del kernel sta pianificando attività che possono essere thread all'interno di un processo multi-thread, o il singolo thread principale di un processo a thread singolo (in quel caso, chiamerai "process" quel singolo thread) o thread del kernel. Probabilmente non vuoi avere più di mille attività programmabili sul tuo sistema desktop.

Su Linux, un processo è semplicemente un gruppo di thread che condividono lo stesso spazio di indirizzi virtuale (e condividono alcune altre cose, come la tabella dei descrittori di file, ecc ...). Alcuni processi hanno solo un thread.

Uno spazio di indirizzi virtuali è definito da Wikipedia come

"l'insieme di intervalli di indirizzi virtuali che un sistema operativo mette a disposizione di un processo"

(ma vedi anche questa risposta che spiega che la terminologia non è universale e che alcuni documenti Microsoft utilizzano una definizione diversa e incompatibile ).

Su Linux, proc (5) è utile per comprendere lo spazio di indirizzi virtuale di alcuni processi. Prova entrambi
cat /proc/self/mapse cat /proc/$$/mapsin un terminale. Vedi anche questo e pmap (1) & ps (1) e top (1) .

Tutti i programmi di spazio utente sono in esecuzione in alcuni processi e utilizzano la memoria virtuale, quindi ogni processo ha il suo spazio di indirizzi virtuale. La RAM fisica è una risorsa gestita dal kernel Linux e le applicazioni non hanno accesso diretto alla RAM (ad eccezione di mmap (2) -ing /dev/mem, vedi mem (4) ).

Quindi un processo non utilizza direttamente la RAM. Utilizza la memoria virtuale e ha il suo spazio di indirizzi virtuale. Il kernel utilizza il paging per gestire le pagine RAM fisiche e fornire lo spazio degli indirizzi virtuali e le astrazioni del processo . In qualsiasi momento (anche quando il processo è inattivo o quando è in esecuzione) il kernel potrebbe sfogliare alcune pagine (ad esempio, scambiarle sul disco). Il kernel sta configurando la MMU (e gestendo le eccezioni hardware mancanti della pagina in alcuni gestori di interrupt , recuperando la pagina dal disco o propagando un errore di segmentazione al processo, vedere segnale (7) )

Potresti avere thread verdi sopra i thread di sistema (ma le librerie di thread verdi sono difficili da implementare e eseguire il debug). Dai un'occhiata alle goroutine usate in Go per un esempio di fantasia. Vedi anche setcontext (3) .

A volte, il tuo sistema potrebbe sperimentare il thrashing . Ciò accade quando la memoria virtuale totale (necessaria per tutti i processi) supera, per un grande fattore, la RAM fisica disponibile. Quindi il tuo computer non risponde. Informazioni su dimensioni del set di residenti , paging della domanda , set di lavoro , sovraccarico di memoria , ASLR .

Vedi anche -per Linux- fork (2) , clone (2) , mmap (2) , madvise (2) , posix_fadvise (2) , mlock (2) , execve (2) , credenziali (7) , pthreads (7) , futex (7) , capacità (7) .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.