GNU/Linux >> Znalost Linux >  >> Linux

Ztráta času execv() a fork()

Už ne. Existuje něco, co se nazývá COW (Copy On Write), pouze když se jeden ze dvou procesů (Rodič/Dítě) pokusí zapsat do sdílených dat, dojde ke zkopírování.

V minulosti:
fork() systémové volání zkopírovalo adresní prostor volajícího procesu (rodiče) a vytvořilo nový proces (potomek). Kopírování adresového prostoru rodiče do potomka bylo nejdražší částí fork() operace.

Nyní:
Volání na číslo fork() je často téměř okamžitě následováno voláním exec() v dětském procesu, který nahradí paměť dítěte novým programem. To je to, co shell obvykle dělá, například. V tomto případě je čas strávený kopírováním adresového prostoru rodiče z velké části promarněn, protože podřízený proces před voláním exec() spotřebuje velmi málo své paměti. .

Z tohoto důvodu pozdější verze Unixu využívaly hardware virtuální paměti, aby umožnily rodičům a potomkům sdílet paměť mapovanou do jejich příslušných adresových prostorů, dokud ji jeden z procesů skutečně nezmění. Tato technika je známá jako copy-on-write . Chcete-li to provést, na fork() jádro by zkopírovalo mapování adresního prostoru z nadřazeného na potomka místo obsahu mapovaných stránek a zároveň by nyní sdílené stránky označilo pouze pro čtení. Když se jeden z těchto dvou procesů pokusí zapsat na jednu z těchto sdílených stránek, dojde k chybě stránky. V tomto okamžiku si unixové jádro uvědomí, že stránka byla skutečně „virtuální“ nebo „kopie při zápisu“, a tak vytvoří novou, soukromou, zapisovatelnou kopii stránky pro chybující proces. Tímto způsobem se obsah jednotlivých stránek ve skutečnosti nezkopíruje, dokud se na ně skutečně nezapíše. Tato optimalizace vytvoří fork() následuje exec() v dítěti mnohem levnější:dítě pravděpodobně bude muset zkopírovat pouze jednu stránku (aktuální stránku svého zásobníku), než zavolá exec() .


Jaká je výhoda, které je dosaženo použitím tohoto komba (místo nějakého jiného řešení), díky kterému to lidé stále používají, i když máme odpad?

Musíte nějakým způsobem vytvořit nový proces. Existuje jen velmi málo způsobů, jak toho může program v uživatelském prostoru dosáhnout. POSIX míval vfork() alognside fork() a některé systémy mohou mít své vlastní mechanismy, jako je například clone() specifický pro Linux , ale od roku 2008 POSIX specifikuje pouze fork() a posix_spawn() rodina. fork + exec cesta je tradičnější, je dobře srozumitelná a má několik nevýhod (viz níže). posix_spawn rodina je navržena jako speciální náhrada za použití v kontextech, které představují potíže pro fork(); podrobnosti naleznete v části "Odůvodnění" jeho specifikace.

Tento výňatek z manuálové stránky Linuxu pro vfork() může svítit:

V systému Linux fork (2) je implementováno pomocí stránek typu copy-on-write, takže jedinou penalizací je fork (2) je čas a paměť potřebná k duplikování rodičovských tabulek stránek a k vytvoření jedinečné struktury úkolů pro dítě . Nicméně, za starých časů fork (2) by vyžadovalo vytvoření úplné kopie datového prostoru volajícího, často zbytečně, protože obvykle bezprostředně poté exec (3) je hotovo. Pro větší efektivitu tedy BSD zavedlo vfork () systémové volání, které plně nezkopírovalo adresní prostor nadřazeného procesu, ale vypůjčilo si paměť a podproces kontroly nadřazeného procesu až do volání execve (2) nebo došlo k odchodu. Nadřazený proces byl pozastaven, zatímco dítě využívalo své prostředky. Použití vfork () bylo složité:například neupravování dat v nadřazeném procesu záviselo na znalosti, které proměnné jsou uloženy v registru.

(Zdůraznění přidáno)

Vaše obava z plýtvání tedy není pro moderní systémy (neomezující se na Linux) opodstatněná, ale historicky to byl skutečně problém a skutečně existovaly mechanismy, jak se tomu vyhnout. V dnešní době je většina těchto mechanismů zastaralá.


Další odpověď uvádí:

Avšak za starých špatných časů by fork(2) vyžadoval vytvoření úplné kopie datového prostoru volajícího, často zbytečně, protože obvykle bezprostředně poté se provede exec(3).

Je zřejmé, že špatné staré časy jednoho člověka jsou mnohem mladší, než si ostatní pamatují.

Původní UNIXové systémy neměly paměť pro běh více procesů a neměly MMU pro udržení několika procesů ve fyzické paměti připravených ke spuštění na stejném logickém adresovém prostoru:vyměnily procesy na disk, který nebyl aktuálně běží.

Systémové volání vidlice bylo téměř úplně stejné jako výměna aktuálního procesu na disk, kromě návratové hodnoty a ne nahrazením zbývající kopie v paměti výměnou v jiném procesu. Vzhledem k tomu, že jste stejně museli zaměnit nadřazený proces, abyste mohli spustit podřízený proces, fork+exec nezpůsobilo žádnou režii.

Je pravda, že existovalo období, kdy bylo fork+exec nepohodlné:kdy existovaly MMU, které poskytovaly mapování mezi logickým a fyzickým adresovým prostorem, ale chyby stránek neuchovávaly dostatek informací, které by umožňovaly kopírování při zápisu a řadu dalších virtuálních -schéma stránkování paměti/vyžadování byla proveditelná.

Tato situace byla dostatečně bolestivá, a to nejen pro UNIX, protože zpracování chyb stránek na hardwaru bylo přizpůsobeno tak, aby bylo "přehratelné" velmi rychle.


Linux
  1. Získat čas uživatele a jádra běžícího procesu?

  2. Čas zahájení procesu s časovým pásmem?

  3. Stavy procesu Linuxu

  1. Rozdíl mezi CLOCK_REALTIME a CLOCK_MONOTONIC?

  2. Rozdíl mezi fork(), vfork(), exec() a clone()

  3. Systémové volání fork() a funkce execv

  1. Najděte čas provedení příkazu nebo procesu v systému Linux

  2. Získejte aktuální čas v hodinách a minutách

  3. PHP a mod_fcgid:ap_pass_brigade se nezdařilo ve funkci handle_request_ipc