Perché la creazione di un nuovo processo è più costosa su Windows rispetto a Linux?


101

Ho sentito che creare un nuovo processo su una macchina Windows è più costoso che su Linux. È vero? Qualcuno può spiegare le ragioni tecniche per cui è più costoso e fornire eventuali ragioni storiche per le decisioni di progettazione alla base di tali ragioni?

Risposte:


68

mweerden: NT è stato progettato per il multiutente sin dal primo giorno, quindi non è proprio un motivo. Tuttavia, hai ragione sul fatto che la creazione di processi gioca un ruolo meno importante su NT che su Unix poiché NT, a differenza di Unix, preferisce il multithreading al multiprocessing.

Rob, è vero che fork è relativamente economico quando viene usato COW, ma in realtà fork è per lo più seguito da un exec. E anche un dirigente deve caricare tutte le immagini. Discutere le prestazioni del fork quindi è solo una parte della verità.

Quando si discute della velocità di creazione del processo, è probabilmente una buona idea distinguere tra NT e Windows / Win32. Per quanto riguarda NT (cioè il kernel stesso), non credo che la creazione di processi (NtCreateProcess) e la creazione di thread (NtCreateThread) siano significativamente più lente rispetto a Unix medio. Potrebbe succedere un po 'di più, ma qui non vedo il motivo principale della differenza di prestazioni.

Se guardi Win32, tuttavia, noterai che aggiunge un bel po 'di overhead alla creazione del processo. Per uno, richiede che il CSRSS riceva una notifica sulla creazione del processo, che coinvolge LPC. Richiede almeno il caricamento aggiuntivo di kernel32 e deve eseguire una serie di elementi di lavoro di contabilità aggiuntivi da eseguire prima che il processo sia considerato un processo Win32 a tutti gli effetti. E non dimentichiamoci di tutto il sovraccarico aggiuntivo imposto dall'analisi dei manifesti, controllando se l'immagine richiede uno shim di compatibilità, controllando se le politiche di restrizione del software si applicano, yada yada.

Detto questo, vedo il rallentamento generale nella somma di tutte quelle piccole cose che devono essere fatte oltre alla creazione grezza di un processo, spazio VA e thread iniziale. Ma come detto all'inizio, a causa del vantaggio del multithreading rispetto al multitasking, l'unico software che risente seriamente di questa spesa aggiuntiva è il software Unix con porting scadente. Sebbene questa situazione cambi quando software come Chrome e IE8 riscoprono improvvisamente i vantaggi del multiprocessing e iniziano ad avviare e smontare frequentemente processi ...


8
Fork non è sempre seguito da exec () e le persone si preoccupano solo di fork (). Apache 1.3 usa fork () (senza exec) su Linux e thread su Windows, anche se in molti casi i processi vengono forkati prima che siano necessari e tenuti in un pool.
Blaisorblade

5
Senza dimenticare, naturalmente, il comando "vfork", progettato per lo scenario "just call exec" che descrivi.
Chris Huang-Leaver,

4
Un altro tipo di software che è seriamente influenzato da questo è qualsiasi tipo di script di shell che coinvolge il coordinamento di più processi. Lo scripting di Bash all'interno di Cygwin, ad esempio, ne soffre molto. Considera un ciclo di shell che genera molti sed, awk e grep nelle pipeline. Ogni comando genera un processo e ogni pipe genera una subshell e un nuovo processo in quella subshell. Unix è stato progettato pensando a questo tipo di utilizzo, motivo per cui la creazione di processi veloci rimane la norma lì.
Dan Molding,

5
-1. L'affermazione che il software è "mal portato" perché non funziona bene su un sistema operativo mal progettato pieno di problemi di compatibilità che rallenta la creazione del processo è ridicola.
Miglia rotta

6
@MilesRout l'obiettivo del porting è modificare il software per eseguirlo su un nuovo sistema di destinazione, tenendo a mente i punti di forza e le carenze di quel sistema. Il software con porting con prestazioni scadenti è un software con porting inadeguato, indipendentemente dai blocchi che il sistema operativo fornisce.
Dizzyspiral

28

Unix ha una chiamata di sistema "fork" che "divide" il processo corrente in due e fornisce un secondo processo identico al primo (modulo il ritorno dalla chiamata fork). Poiché lo spazio degli indirizzi del nuovo processo è già attivo e in esecuzione, dovrebbe essere più economico che chiamare "CreateProcess" in Windows e caricare l'immagine exe, le DLL associate, ecc.

Nel caso del fork, il sistema operativo può utilizzare la semantica "copia su scrittura" per le pagine di memoria associate a entrambi i nuovi processi per garantire che ciascuno riceva la propria copia delle pagine che successivamente modificano.


22
Questo argomento vale solo quando stai davvero biforcando. Se stai iniziando un nuovo processo, su Unix devi ancora eseguire il fork ed eseguire. Sia Windows che Unix hanno copia in scrittura. Windows riutilizzerà sicuramente un EXE caricato se esegui una seconda copia di un'app. Non credo che la tua spiegazione sia corretta, mi dispiace.
Joel Spolsky


Ho aggiunto alcuni dati sulle prestazioni nella mia risposta. stackoverflow.com/a/51396188/537980 Puoi vedere che è più veloce.
ctrl-alt-delor

25

In aggiunta a ciò che ha detto JP: la maggior parte del sovraccarico appartiene all'avvio di Win32 per il processo.

Il kernel di Windows NT supporta effettivamente il fork COW. SFU (ambiente UNIX di Microsoft per Windows) li utilizza. Tuttavia, Win32 non supporta il fork. I processi SFU non sono processi Win32. SFU è ortogonale a Win32: sono entrambi sottosistemi di ambiente costruiti sullo stesso kernel.

Oltre alle chiamate LPC out-of-process CSRSS, in XP e versioni successive è presente una chiamata out of process al motore di compatibilità dell'applicazione per trovare il programma nel database di compatibilità dell'applicazione. Questo passaggio causa un sovraccarico sufficiente che Microsoft fornisce un'opzione di criteri di gruppo per disabilitare il motore di compatibilità su WS2003 per motivi di prestazioni.

Le librerie di runtime Win32 (kernel32.dll, ecc.) Eseguono anche molte letture del registro e inizializzazioni all'avvio che non si applicano a UNIX, SFU o processi nativi.

I processi nativi (senza sottosistema di ambiente) sono molto veloci da creare. SFU fa molto meno di Win32 per la creazione dei processi, quindi anche i suoi processi sono veloci da creare.

AGGIORNAMENTO PER IL 2019: aggiungi LXSS: sottosistema Windows per Linux

La sostituzione di SFU per Windows 10 è il sottosistema dell'ambiente LXSS. È in modalità kernel al 100% e non richiede nessuno degli IPC che Win32 continua ad avere. Syscall per questi processi è diretto direttamente a lxss.sys / lxcore.sys, quindi fork () o un altro processo che crea una chiamata costa solo 1 chiamata di sistema per il creatore, in totale. [Un'area dati chiamata istanza] tiene traccia di tutti i processi, thread e stato di runtime LX.

I processi LXSS si basano su processi nativi, non su processi Win32. Tutte le cose specifiche di Win32 come il motore di compatibilità non sono affatto coinvolte.


16

Oltre alla risposta di Rob Walker: Al giorno d'oggi hai cose come la Native POSIX Thread Library, se vuoi. Ma per molto tempo l'unico modo per "delegare" il lavoro nel mondo unix è stato usare fork () (ed è ancora preferito in molte, molte circostanze). ad esempio una specie di server socket

socket_accept ()
forchetta()
se (bambino)
    handleRequest ()
altro
    goOnBeingParent ()
Pertanto l'implementazione del fork doveva essere veloce e nel tempo sono state implementate molte ottimizzazioni. Microsoft ha approvato CreateThread o anche fibre invece di creare nuovi processi e utilizzare la comunicazione tra processi. Penso che non sia "giusto" confrontare CreateProcess con il fork poiché non sono intercambiabili. Probabilmente è più appropriato confrontare fork / exec con CreateProcess.


2
Riguardo al tuo ultimo punto: fork () non è intercambiabile con CreateProcess (), ma si può anche dire che Windows dovrebbe implementare fork () allora, perché questo offre maggiore flessibilità.
Blaisorblade

Ah, il verbo To Bee.
acib708

Ma fork + exec in Linux, è più veloce di CreateThread su MS-Windows. E Linux può fare il fork da solo per essere ancora più veloce. Comunque la confronti, la SM è più lenta.
ctrl-alt-delor

13

La chiave di questa questione è l'uso storico di entrambi i sistemi, credo. Windows (e DOS prima ancora) erano originariamente sistemi monoutente per personal computer. In quanto tali, questi sistemi in genere non devono creare molti processi tutto il tempo; In poche parole, un processo viene creato solo quando questo utente solitario lo richiede (e noi umani non operiamo molto velocemente, relativamente parlando).

I sistemi basati su Unix erano originariamente sistemi e server multiutente. Soprattutto per questi ultimi non è raro avere processi (es. Posta o demoni http) che suddividono processi per gestire lavori specifici (es. Prendersi cura di una connessione in entrata). Un fattore importante per fare ciò è il forkmetodo economico (che, come menzionato da Rob Walker ( 47865 ), utilizza inizialmente la stessa memoria per il processo appena creato) che è molto utile in quanto il nuovo processo ha immediatamente tutte le informazioni di cui ha bisogno.

È chiaro che, almeno storicamente, la necessità per i sistemi basati su Unix di avere una creazione rapida dei processi è molto maggiore rispetto ai sistemi Windows. Penso che sia ancora così perché i sistemi basati su Unix sono ancora molto orientati ai processi, mentre Windows, a causa della sua storia, è stato probabilmente più orientato ai thread (i thread sono utili per creare applicazioni reattive).

Disclaimer: non sono affatto un esperto in materia, quindi perdonami se ho sbagliato.


9

Uh, sembra che ci siano molte giustificazioni "è meglio così" in corso.

Penso che le persone potrebbero trarre beneficio dalla lettura di "Showstopper"; il libro sullo sviluppo di Windows NT.

L'intera ragione per cui i servizi vengono eseguiti come DLL in un processo su Windows NT è che erano troppo lenti come processi separati.

Se ti sporchi e ti sporchi, scoprirai che il problema è la strategia di caricamento della libreria.

Su Unix (in generale) i segmenti di codice delle librerie condivise (DLL) sono effettivamente condivisi.

Windows NT carica una copia della DLL per processo, poiché manipola il segmento di codice della libreria (e il segmento di codice eseguibile) dopo il caricamento. (Gli dice dove sono i tuoi dati?)

Ciò si traduce in segmenti di codice nelle librerie che non sono riutilizzabili.

Quindi, la creazione del processo NT è in realtà piuttosto costosa. E sul lato negativo, non rende apprezzabile il risparmio di memoria della DLL, ma una possibilità per problemi di dipendenza tra le app.

A volte in ingegneria paga fare un passo indietro e dire: "ora, se dovessimo progettarlo per fare davvero schifo, come sarebbe?"

Ho lavorato con un sistema incorporato che era piuttosto capriccioso una volta, e un giorno l'ho guardato e ho capito che era un magnetron a cavità, con l'elettronica nella cavità delle microonde. Lo abbiamo reso molto più stabile (e meno simile a un microonde).


3
I segmenti di codice sono riutilizzabili fintanto che la DLL viene caricata nel suo indirizzo di base preferito. Tradizionalmente dovresti assicurarti di impostare indirizzi di base non in conflitto per tutte le DLL che verrebbero caricate nei tuoi processi, ma questo non funziona con ASLR.
Mike Dimmick

C'è qualche strumento per rebase tutte le DLL, non è vero? Non sono sicuro di cosa fa con ASLR.
Zan Lynx,

3
La condivisione delle sezioni di codice funziona anche sui sistemi abilitati per ASLR.
Johannes che passa il

@MikeDimmick, quindi tutti coloro che creano una DLL devono collaborare per assicurarsi che non ci siano conflitti, o li patcha tutti a livello di sistema, prima di caricarli?
ctrl-alt-delor

9

La risposta breve è "livelli e componenti software".

L'architettura SW di Windows ha un paio di livelli e componenti aggiuntivi che non esistono su Unix o sono semplificati e gestiti all'interno del kernel su Unix.

Su Unix, fork ed exec sono chiamate dirette al kernel.

Su Windows, l'API del kernel non viene utilizzata direttamente, c'è win32 e alcuni altri componenti sopra di essa, quindi la creazione del processo deve passare attraverso livelli aggiuntivi e quindi il nuovo processo deve essere avviato o connettersi a quei livelli e componenti.

Per un po 'di tempo i ricercatori e le aziende hanno tentato di rompere Unix in un modo vagamente simile, basando solitamente i loro esperimenti sul kernel Mach ; un esempio ben noto è OS X .. Ogni volta che ci provano, però, diventa così lento che finiscono per unire almeno parzialmente i pezzi nel kernel in modo permanente o per le spedizioni di produzione.


I livelli non rallentano necessariamente le cose: ho scritto un driver di dispositivo, con molti livelli, in C. Codice pulito, programmazione alfabetizzata, facile da leggere. Era più veloce (marginalmente) di una versione scritta in un assemblatore altamente ottimizzato, senza strati.
ctrl-alt-delor

L'ironia è che NT è un kernel enorme (non un micro kernel)
ctrl-alt-delor

2

Poiché sembra esserci qualche giustificazione di MS-Windows in alcune delle risposte, ad es

  • “Il kernel NT e Win32 non sono la stessa cosa. Se programmi sul kernel NT, non è poi così male ”- Vero, ma a meno che tu non stia scrivendo un sottosistema Posix, allora chi se ne frega. Scriverai a win32.
  • "Non è giusto confrontare il fork, con ProcessCreate, poiché fanno cose diverse e Windows non ha il fork" - Vero, quindi confronterò simili con simili. Tuttavia confronterò anche il fork, perché ha molti molti casi d'uso, come l'isolamento dei processi (ad esempio, ogni scheda di un browser web viene eseguita in un processo diverso).

Ora guardiamo ai fatti, qual è la differenza di prestazioni?

Dati estrapolati da http://www.bitsnbites.eu/benchmarking-os-primitives/ .
Poiché il bias è inevitabile, riassumendo, l'ho fatto a favore dell'hardware MS-Windows
per la maggior parte dei test i7 8 core 3.2GHz. Tranne Raspberry-Pi con Gnu / Linux

Un confronto di varie operazioni di base, su Gnu / Linux, Apple-Mac e Microsoft Windows (più piccolo è meglio)

Un confronto tra la creazione di processi di MS-Windows e Linux

Note: su Linux, forkè più veloce del metodo preferito da MS-Window CreateThread.

Numeri per le operazioni del tipo di creazione del processo (perché è difficile vedere il valore per Linux nel grafico).

In ordine di velocità, dal più veloce al più lento (i numeri sono il tempo, piccolo è meglio).

  • Linux CreateThread 12
  • Mac CreateThread 15
  • Forcella Linux 19
  • Windows CreateThread 25
  • Linux CreateProcess (fork + exec) 45
  • Mac Fork 105
  • Mac CreateProcess (fork + exec) 453
  • Raspberry-Pi CreateProcess (fork + exec) 501
  • Windows CreateProcess 787
  • Windows CreateProcess con antivirus 2850
  • Windows Fork (simula con CreateProcess + fixup) maggiore di 2850

Numeri per altre misurazioni

  • Creazione di un file.
    • Linux 13
    • Mac 113
    • Windows 225
    • Raspberry-Pi (con scheda SD lenta) 241
    • Windows con defender e antivirus, ecc. 12950
  • Allocazione della memoria
    • Linux 79
    • Windows 93
    • Mac 152

1

Tutto ciò in più c'è il fatto che sulla macchina Win molto probabilmente un software antivirus entrerà in funzione durante il CreateProcess ... Di solito è il rallentamento più grande.


1
Sì, è il rallentamento più grande, ma non l'unico significativo.
ctrl-alt-delor

1

Vale anche la pena notare che il modello di sicurezza in Windows è molto più complicato rispetto ai sistemi operativi basati su unix, il che aggiunge molto overhead durante la creazione del processo. Ancora un altro motivo per cui il multithreading è preferito al multiprocessing in Windows.


1
Mi aspetto che un modello di sicurezza più complicato sia più sicuro; ma i fatti mostrano il contrario.
Lie Ryan

4
SELinux è anche un modello di sicurezza molto complesso e non impone un sovraccarico significativo sufork()
Spudd86

6
@LieRyan, Nella progettazione del software (nella mia esperienza), più complicato molto raramente significa più sicuro.
Woodrow Douglass il
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.