JUI - 5. přednáška Modifikace struktur, reprezentace atomů, vstup/výstup, ovládání paměti RNDr. Jiří Dvořák, CSc.
2 Modifikace struktur Ve striktně chápaném paradigmatu funkcionálního programování se datové struktury pouze vytvářejí a jako celek pak mohou být zařazovány do vyšších struktur nebo být zrušeny, nelze je však měnit. Každá sebenepatrnější modifikace struktury znamená v takovém případě její kompletní rekonstrukci (t.j. nové vytvoření), i když se bude lišit např. jen v záměně jednoho atomu za jiný. Tento přístup by v praktických aplikacích mohl vést k neúnosným časovým nárokům nebo ke zbytečnému čerpání buněk volné paměti (což se v konečném efektu projeví m.j. opět zpomalením výpočtu). Jazyk Lisp proto dává uživateli možnost modifikovat existující datové struktury.
3 Funkce pro modifikaci struktur rplaca nahrazení 1. části tečky-dvojice rplacd nahrazení 2. části tečky-dvojice nconc spojení seznamů setf obdoba setq mapcan obdoba mapcar mapcon obdoba maplist
4 Funkce rplaca a rplacd Názvy těchto pseudofunkcí jsou odvozeny z anglických výrazů „replace car“ a „replace cdr“, které vyjadřují jejich sémantiku. (rplaca forma-tečka-dvojice forma-nový-car) Tato funkce modifikuje 1. část tečky-dvojice tak, že do ní uloží odkaz na nový-car. Dojde tedy k náhradě prvního prvku tečky- dvojice za jiný, ale nestane se tak vytvořením nové tečky-dvojice, nýbrž modifikací původní struktury. (rplacd forma-tečka-dvojice forma-nový-cdr) Tato funkce modifikuje 2. část tečky-dvojice tak, že do ní uloží odkaz na nový-cdr.
5 Funkce nconc a setf nconc Funkce nconc může mít proměnný počet argumentů. Hodnotami argumentů musejí být seznamy a výsledkem je seznam vzniklý spojením těchto seznamů. Přitom se změní struktura všech argumentů kromě posledního, což se projeví také ve všech strukturách, do nichž byly příslušné S-výrazy dříve začleněny. setf Funkce setf má dva argumenty. První musí určovat nějaké místo“ a druhý určuje hodnotu, která se na toto „místo“ dosadí. Následující zápisy jsou tedy sémanticky ekvivalentní (rplaca X Y) = (setf (car X) Y) (rplacd X Y) = (setf (cdr X) Y)
6 Funkcionály mapcan a mapcon mapcan Funguje jako funkcionál mapcar, ale vrací seznam vzniklý spojením dílčích výsledků pomocí funkce nconc. mapcon Funguje jako maplist, ale vrací seznam vzniklý spojením dílčích výsledků pomocí funkce nconc. Sémantiku těchto funkcionálů je tedy možné charakterizovat pomocí ekvivalencí (mapcan Fce Lst) (apply 'nconc (mapcar Fce Lst)) (mapcon Fce Lst) (apply 'nconc (maplist Fce Lst))
7 Reprezentace atomů Při grafickém znázornění paměťové reprezentace symbolických výrazů Lispu je odkaz na atom vyjadřován šipkou směřující ke jménu daného atomu. Zdálo by se, že k paměťové reprezentaci symbolického atomu bude stačit uložení příslušného řetězu znaků. Jméno je však pouze jednou z tzv. vlastností atomu a každý symbolický atom může mít libovolný počet vlastností. Některé z vlastností atomu využívá Lisp automaticky při zpracování programu – takové vlastnosti označujeme jako standardní. Vedle standardních vlastností může uživatel přiřadit atomu libovolné další vlastnosti a využívat jich podle vlastní úvahy. Tato možnost spolu s jednoznačnou reprezentací symbolických atomů v Lispu poskytuje zcela nové programovací možnosti, které tvoří základ pro daty řízené programování a objektově orientované programování.
8 Seznam vlastností atomu Symbolický atom reprezentuje seznam vlastností atomu (property- list, zkráceně P-seznam). Reprezentace atomu v paměti je tedy obdobná jako reprezentace neatomických S-výrazů a je založena na využití cons-buněk. P-seznam nelze ovšem chápat jako obyčejný seznam, neboť je to vnitřní reprezentace atomu. Struktura reprezentující symbolický atom se vytvoří při prvním výskytu daného atomu v programu nebo v datech, a od té chvíle se každý další výskyt vyjádří odkazem na tuto jedinou reprezentaci. Přestože všechny výskyty daného atomu reprezentuje jediná paměťová struktura, neznamená to, že tato struktura zůstává během výpočtu neměnná. Pro číselné atomy jedinečnost reprezentace neplatí. Protože číselný atom představuje pouze příslušnou číselnou hodnotu, týká se možnost existence různých vlastností pouze symbolických atomů.
9 Příklady standardních vlastností atomů PNAME – hodnotou je řetězec znaků tvořící jméno atomu (print- name). APVAL – slouží pro uložení hodnoty navázané na proměnnou EXPR – slouží k uložení uživatelské definice funkce; její hodnotou je příslušný lambda-výraz. SUBR – slouží k uložení odkazu na funkci ve strojovém kódu. FEXPR – charakterizuje atom jako speciální funkci a za hodnotu má příslušnou lambda-definici. FSUBR – charakterizuje atom jako standardní speciální funkci a za hodnotu má odkaz na její realizaci ve strojovém kódu. Tentýž atom může být vázanou proměnnou i jménem funkce a kontext jeho použití rozhoduje, kterou interpretaci systém Lisp použije. Vlastnosti EXPR a FEXPR (a ovšem též SUBR a FSUBR) se u jednoho atomu nemohou vyskytovat současně.
10 Funkce pro získání hodnoty vlastnosti a zrušení vlastnosti (get symbol-forma indikátor-forma) Funkce get má dva argumenty. Hodnotou prvého by měl být symbolický atom a hodnotou druhého indikátor vlastnosti z P- seznamu daného atomu. Výsledkem je hodnota vlastnosti s určeným indikátorem. Pokud daný atom požadovanou vlastnost nemá, je výsledkem nil. (remprop symbol-forma indikátor-forma) Funkce remprop zajistí vypuštění vlastnosti určené indikátorem (včetně její hodnoty) z P-seznamu daného symbolického atomu. Tato funkce vrací nil.
11 Vložení hodnoty do seznamu vlastností (putprop symbol-forma hodnota-forma indikátor-forma) Funkce putprop zajistí uložení hodnoty vlastnosti určené indikátorem vlastnosti do P-seznamu daného symbolického atomu. Tato funkce vrací ukládanou hodnotu. V jazyku Common Lisp tato funkce chybí. Vložení hodnoty do seznamu vlastností se zajišťuje pomocí kombinace funkcí setf a get: (setf (get symbol-forma indikátor-forma) hodnota-forma)
12 Funkce gensym (gensym) Hodnotou aplikace funkce gensym bez argumentů je vygenerovaný atom. Jeho jméno je tvořeno aktuálně platným prefixem (implicitně G) za nímž následuje aktuální pořadové číslo (na počátku 1). Po každém volání funkce gensym se zvětšuje pořadové číslo, takže je zaručena různost generovaných atomů. (gensym výraz) Hodnota argumentu určuje jméno generovaného atomu takto: je-li hodnotou symbolický atom, uloží se jako aktuálně platný prefix a teprve pak se generuje požadovaný atom, je-li hodnotou nezáporné celé číslo, uloží se jako aktuální pořadové číslo a teprve pak se generuje požadovaný atom.
13 Vstup/výstup z/do standardních zařízení (read) Funkce read přečte ucelený S-výraz a ten vrátí jako výslednou hodnotu. (print výraz) (prin1 výraz) (princ výraz) Tyto funkce vypíší hodnotu argumentu (zobrazený S-výraz je současně výslednou hodnotou těchto funkcí). Funkce print pak přejde na nový řádek. Funkce print a prin1 zobrazí hodnotu argumentu ve tvaru, který je zpětně čitelný pomocí funkce read. (terpri) Funkce terpri ukončí aktuální řádek a vrátí nil.
14 Vstup/výstup z/do souborů (open jméno-souboru) Funkce open zajistí otevření souboru. Jméno souboru je symbol nebo řetězec. Funkce vrací soubor (ukazatel na soubor). (close soubor) Funkce close zajistí uzavření souboru. (read soubor) (print výraz soubor) (prin1 výraz soubor) (princ výraz soubor) (terpri soubor)
15 Ovládání paměti Algoritmy ovládání paměti tvoří nedílnou součást programovacích technik a využívají se nejen jako standardní podpora v implementacích programovacích jazyků, ale také např. v operačních systémech. Princip automatického ovládání paměti zavedený v Lispu byl zásadním podnětem pro rozvoj těchto algoritmů, a tak byla většina nových principů a nejdůležitějších metod zavedena právě v souvislosti s implementací nějaké varianty Lispu. Společným rysem různých metod garbage-collection je, že přidělování paměti objektům postupuje tak dlouho, až se vyčerpá určitá disponibilní kapacita. V okamžiku, kdy žádost o přiděleni. paměti nelze uspokojit, se zavolá garbage-collector, který zjistí rozsah paměti obsazené aktivními (tzn. programu dostupnými) objekty a zbývající paměť uvolní pro další použití.
16 Metody ovládání paměti Metoda Stop-and-copy Inkrementální metoda Stop-and-copy Metoda stratifikace objektů Metoda značkování paměti
17 Metoda Stop-and-copy Metoda stop-and-copy se využívá především v implementacích pracujících se systémem virtuální paměti. Základem této metody je rozdělení dynamicky využívané paměti na dvě části stejné velikosti (označme je jako novou oblast a kopírovací oblast). Na počátku práce systému se všechny objekty alokují pouze v nové oblasti, kopírovací oblast zůstává nevyužita. Alokace probíhá sekvenčně od nejnižžších adres. V okamžiku vyvolání garbage-collectoru se z nové oblasti stává stará oblast a všechny aktivní objekty se okopírují do kopírovací oblasti počínaje od jejích nejnižších adres. Současně s tím se ovšem musí zajistit odpovídající úprava všech ukazatelů jak v datech samotných, tak i ve výchozí množině registrů a zásobníku. Po skončení kopírování s úpravami se z kopírovací oblasti stane nová oblast ze staré oblasti se stává kopírovací oblast pro příští etapu.
18 Výhody a nevýhody metody Stop-and-copy Výhody: Efektivnost práce s virtuální pamětí (procházejí se pouze kořenová místa a aktivní objekty, takže se redukuje výměna stránek mezi diskem a pamětí). Scelování paměti (všechny objekty se do kopírovací oblasti ukládají sekvenčně, což má kladný vliv na fragmentaci dat a tím i na potřebu výměny stránek při pozdějším pokračování ve výpočtu). Nevýhody: Plýtvání pamětí (fakticky se využívá jen polovina dostupné paměti; v případě virtuální paměti to však není tak důležité). Doba trvání (při použití této metody se výpočet zastaví a pokračuje až po dokončení celého kopírování; to může způsobit nepřípustné zpoždění u aplikací, které vyžadují odezvu v reálném čase).
19 Inkrementální metoda Stop-and-copy Inkrementální metoda se provádí souběžně s výpočtem lispovského programu. Paměť se dělí na tři oblasti – starou, kopírovací a novou. Do kopírovací oblasti se přesunou pouze kořenové objekty ze staré oblasti. V tomto okamžiku se obnoví výpočet programu. Při výpočtu se každý ukazatel vyzvednutý z paměti kontroluje, zda neobsahuje adresu patřící do nelegální staré oblasti. Je-li tomu tak, zavolá se garbage-collector, aby příslušný objekt okopíroval ze staré do nové oblasti. Současně s tím je účelné nakopírovat i nějaké objekty ze staré do kopírovací oblasti, aby se využilo zdržení způsobené voláním kopírovače. Je ovšem třeba zajistit, že garbage-collection skončí dřív, než se vyčerpá celá nová oblast a bude vyžadovat nové provedení garbage-collection. Toho lze dosáhnout tak, že s každou alokací objektu délky n slov v nové oblasti spojíme přesun alespoň k * n slov ze staré do kopírovací oblasti.
20 Výhody a nevýhody inkrementální metody Nejdelší prodleva v případě této varianty garbage-collection je úměrná době potřebné na okopírování největšího objektu, což představuje velmi malý zlomek doby trvání celého procesu kopírování. Taková prodleva už nemusí být překážkou k dosažení stanovené doby odezvy programu pro aplikace pracující v reálném čase. Tento zisk je ovšem zaplacen nejen zvýšenými časovými nároky plynoucími z opakovaného vyvolávání kopírovače, ale hlavně nutností kontrolovat každý výběr ukazatele z paměti! Tento problém řeší speciální lispovské architektury zabudováním potřebné kontroly do hardwarové úrovně, takže reference staré oblasti pak vyvolá reakci analogickou s výpadkem stránky. U standardních architektur by však taková kontrola vyžadovala provedení několika instrukcí, což činí tuto variantu v takovém případě nepřijatelnou.
21 Metoda stratifikace objektů Metoda stratifikace objektů (generation scavenging) je modifikací metody Stop-and-copy. Tato modifikace vychází ze skutečnosti, že datové objekty vznikající během výpočtu lispovského programu vykazují různou dobu životnosti. Základní myšlenkou je vytvoření několika úrovní tzv. efemérních (přechodných) paměťových oblastí. Většina nově vytvořených objektů se ukládá zprvu do relativně malé první efemérní oblasti. Jakmile se tato oblast zaplní, projde se kořenová množina a živé objekty z první efemérní oblasti se přesunou do druhé efemérní oblasti. Když se zaplní druhá oblast, její živé objekty se podobně přesunou do třetí oblasti, atd. Teprve z poslední efemérní oblasti se objekty přesouvají do dynamické oblasti, ve které se garbage-collection provede standardním stop-and-copy algoritmem, pokud to vůbec bude zapotřebí.
22 Výhody a nevýhody metody stratifikace Výhodnost tohoto algoritmu je dána tím, že se soustřeďuje na krátce žijící objekty, zatímco dlouhodobě existující objekty postupují hierarchií efemérních oblastí a nakonec skončí v dynamické oblasti, ve které mohou zůstat až do konce výpočtu programu na stejném místě. Algoritmus je také výhodný v tom, že prohlíží jen malou kořenovou množinu a kopíruje tedy jen málo objektů. Nevýhodou je nutnost kontroly operací nastavení (modifikace) ukazatelů (je nutno ošetřit zpětné reference na efemérní oblasti nižší úrovně). Kontrola nastavení ukazatele na standardní počítačové architektuře vyžaduje provedení několika instrukcí. Z tohoto důvodu se opět výhody této metody projeví výrazněji na speciálních lispovských architekturách. Celkový počet nastavení ukazatelů je však u běžných programů zpravidla řádově menší než jejich výběr, takže se stratifikace s úspěchem uplatňuje i na standardních architekturách.
23 Metoda značkování paměti Metoda značkování paměti (mark and sweep) patří mezi klasické metody garbage-collection. Proberme základní kroky této metody pro zjednodušený případ, kdy se s její pomocí ovládá pouze přidělování cons-buněk. Systém v tomto případě udržuje seznam volné paměti. Vlastní algoritmus garbage-collection má dvě fáze – značkování a sbírání. Během značkování se označí všechny aktivní cons- buňky. Začne se od buněk, na které vedou ukazatele z kořenové množiny a rekurzivně se projdou všechny podřízené struktury. Aby se značkování nezacyklilo, před označením buňky (a jejích podstruktur) se testuje, zda již nebyla označena dříve. Fáze sbírání probíhá tak, že se celá paměťová oblast vyhrazená pro cons-buňky sekvenčně projde od počátku až do konce a všechny buňky, které nejsou označené, se napojí do seznamu volné paměti.
24 Výhody a nevýhody metody značkování Hlavní výhodou je relativní jednoduchost a úplné využití přidělené fyzické paměti. Z těchto důvodů se metoda značkování používá především na malých systémech bez virtuální paměti. Nevýhody: Nároky na zásobník (značkovací fáze potřebuje dostatečné místo v zásobníku; to je možné nahradit průběžným přesměrováním ukazatelů v procházených strukturách). Nároky na uložení značek. Sekvenční sbírání (pro systémy s virtuální pamětí to znamená stránkovací zátěž). Fragmentace paměti (nevytvoří se souvislý blok volné paměti; je třeba provést explicitní fázi scelování volné paměti). Referenční rozpětí (alokací a uvolňováním buněk podle tohoto postupu dochází k velkému rozptýlení datových struktur po paměti).