LINUXZONE






 >> Hlavní stránka

(1713/30.07.2010)


 >> Administrace

(160/29.07.2010)


 >> Literatura

(305/28.07.2010)


 >> Bezpečnost

(340/30.07.2010)


 >> Programování

(307/19.04.2010)


 >> Distribuce

(97/09.06.2010)


 >> Síťování

(86/03.06.2010)


 >> Lokalizace

(10/15.09.2004)


 >> Aplikace

(175/12.04.2010)


 >> Multimedia

(32/31.03.2006)


 >> Hardware

(45/02.03.2007)


 >> Začínáme

(228/24.06.2010)


 >> Aktuálně

(556/27.07.2010)


 >> RELAX

(201/26.07.2010)


 >> Jinde vyšlo

přehled ostatních serverů




 Přihlášení




Login:
Heslo:
 uložit v prohlížeči


Nejste-li ješte zaregistrováni, můžete tak učinit zde.





 Vyhledávání




Hledaný výraz:
v klíčových slovech
v titulku
v anotaci
v textu








 Reklama









 Servis




*   Vaše náměty a připomínky
Máte k Linuxzone.cz nějaké připomínky nebo náměty? Našli jste na stránkách chybu? Dejte nám o tom vědět pomocí formuláře nebo v diskuzi.
Komentářů: 30
*   Podpořte Linuxzone.cz
Chcete podpořit náš server umístěním odkazu nebo zveřejněním backendu? Zde najdete vše potřebné.
*   Pište pro Linuxzone.cz
Máte zájem podílet se na obsahu Linuxzone.cz ať už jako redaktoři nebo i jinak? Dejte nám o sobě vědět!





 Aktuálně z bezpečnosti




-- 
6.12.2005, 19:01
Na serveru informit.com vyšla ukázková kapitola týkající se práce s řetězci z knihy Secure Coding in C and C++. (lz)

-- 
3.12.2005, 12:34
Bugtraq: Format String Vulnerabilities in Perl Programs. (lz)

-- 
3.12.2005, 12:32
Linux Advisory Watch December 2nd 2005. (lz)

-- 
23.10.2005, 13:28
Rozhovor na téma klasické zálohování versus CDP. (lz)

-- 
23.10.2005, 13:24
Linux Advisory Watch October 21st 2005. (lz)

další >>





 Aktuálně o software




-- 
6.12.2005, 19:07
Potřebujete-li pod linuxem rozchodit bezdrát založený na čipsetech Broadcom 43xx, konečně existuje linuxový ovladač. (lz)

-- 
6.12.2005, 19:04
Byla uvolněna verze Xen 3.0.0 virtualizační technologie XEN. (lz)

-- 
6.12.2005, 18:59
Byla uvolněna verze X11R6.9/X11R7 RC 3 grafickérho rozhraní X Window System. (lz)

-- 
3.12.2005, 12:45
Co je nového okolo projektu Amanda (open source zálohovací software)? Více na osnews.com. (lz)

-- 
3.12.2005, 12:40
Jak to akuálně v linuxu vypadá s podporou SATA.. (lz)

další >>





 Aktuálně z IT




-- 
3.12.2005, 12:51
Novellu se daří prodej linuxových produktů, oproti loňskému roku se Novell dočkal výrazného nárůstu. (lz)

-- 
3.12.2005, 12:48
Třetí verzi licence GPL by měla být publikována během jara 2007. (lz)

-- 
23.10.2005, 13:20
V Peru nyní mají zákon, který umožňuje nasazení open source software ve vládní správě. (lz)

-- 
23.10.2005, 13:14
Proč se Microsoft bojí Google? (lz)

-- 
27.9.2005, 22:01
Peru má zákon podporující free software. (lz)

další >>





 Nejčtenější články




-- 
Hurd včera dnes a zítra

-- 
XEN aneb virtualizujeme (3/6)

-- 
Security Digest (15/2010)

-- 
Fotografický ateliér

-- 
XEN aneb virtualizujeme (4/6)

-- 
Novinky ze světa svobodného software (16/2010)

-- 
Gamesárium [138]

-- 
Proč používat svobodný software?

-- 
Velká kniha sportovní fotografie

-- 
Security Digest (16/2010)






 Nejlepší články




-- 
Gamesárium [138]

-- 
Datové struktury bez předchozích znalostí

-- 
XEN aneb virtualizujeme (4/6)

-- 
XEN aneb virtualizujeme (3/6)

-- 
Security Digest (16/2010)

-- 
Novinky ze světa svobodného software (17/2010)

-- 
Velká kniha sportovní fotografie

-- 
XEN aneb virtualizujeme (5/6)

-- 
Security Digest (15/2010)

-- 
Proč používat svobodný software?






 Anketa




Používáte nějaké rozšíření bezpečnostního modelu linuxového jádra?

Openwall (18%)

LIDS (12%)

Pax/Grsecurity (3%)

SELinux (6%)

RSBAC (1%)

jiné (1%)

používám standardní jádro (59%)







Linuxzone.cz - server o Linuxu pro programátory, administrátory a fanoušky.
Provozuje společnost Impossible.
ISSN: 1213-8738





Optimalizace v Lispu

Mezi programátory je široce rozšířena pověra, že programy v Lispu jsou vždy pomalé. Skutečnost je ovšem jiná, Lisp kombinuje některé dobré vlastnosti jazyků se statickým i dynamickým typováním a kromě toho nabízí v oblasti optimalizace i některé vskutku nevšední možnosti, v řadě jiných programovacích jazycích neznámé. Podívejme se, jak široké optimalizační možnosti Lispu jsou a co konkrétně Lisp v tomto směru nabízí.

Pojem optimalizace

Optimalizaci lze chápat velmi široce. Optimalizovat lze algoritmy, kód, práci programátora. Programový kód lze optimalizovat na rychlost, paměť, bezpečnost. V tomto článku se zaměříme na optimalizace obsažené přímo v ANSI standardu jazyka Common Lisp, umožňující efektivní spolupráci programátora s lispovými překladači. Máme tím na mysli optimalizace zdrojového i strojového kódu a optimalizaci práce programátora. Co se týče jiných dialektů Lispu, ty mají zpravidla odlišné optimalizační prostředky a mnohdy se optimalizacemi vůbec nezabývají.

Stabilita kódu

Common Lisp vznikl z potřeby sjednotit mnoho lispových dialektů do jediného, společného jazyka. Přibližně před patnácti lety došlo k jeho stabilizaci, která byla završena roku 1994 schválením ANSI standardu jazyka. Standard dostál svému cíli definovat stabilní jazyk, platí bez jediné změny dodnes a ani v budoucích letech v něm nelze očekávat žádné změny, možná jsou pouze budoucí rozšíření.

Díky stabilitě standardu jsou standardu odpovídající programy v Common Lispu i po mnoha letech použitelné, na rozdíl od některých jiných populárních programovacích jazyků, kde je definice jazyka stále ještě ve vývoji a neustále se mění. Z toho vyplývají první dvě důležité optimalizace.

Optimalizace: Co jednou v Common Lispu napíšete v souladu se standardem jazyka, nemusíte znovu přepisovat.

Optimalizace: Kód odpovídající standardu jazyka můžete zkompilovat libovolným překladačem standard splňujícím. Můžete si tedy ke svému kódu vybrat překladač dle aktuální potřeby.

Interpretovaný nebo kompilovaný?

Jednou z častých pověr týkajících se Lispu je, že se jedná o "interpretovaný" a tudíž pomalý jazyk. Skutečnost je taková, že pojem "interpretovaný" je jednak poněkud nejasný (je tím myšlena interpretace zdrojového textu nebo interpretace byte kódu?) a jednak, že u málokterého jazyka je v jeho definici stanoveno, co se má interpretovat a co se interpretovat nesmí. V případě Common Lispu, stejně jako třeba u jazyka C, nic takového obecně stanoveno není. Některé lispové překladače překládají kód do strojových instrukcí, některé do byte kódu a u některých si můžete způsob překladu vybrat. Interpret zdrojového kódu mi není znám.

Optimalizace: Potřebujete-li, aby výsledný kód běžel co nejrychleji, necháte jej přeložit do strojového kódu. Potřebujete-li, aby kód byl co nejmenší, necháte jej přeložit do byte kódu.

Někteří programátoři se domnívají, že kvůli dynamickému charakteru lispových definic, umožňujících předefinování funkcí za běhu, je nutné, aby Lisp byl pomalý. Skutečnost je v případě Common Lispu taková, že:

  • Naprostá většina posixových programů využívá knihovnu libc, která u svých exportovaných funkcí umožňuje, prostřednictvím obalovacích knihoven, přesně totéž. V souvislosti s tímto faktem jsem stížnosti na pomalost libc dosud neslyšel.
  • Standardní funkce jazyka (kterých je několik set) předefinovány být nesmí. Takové funkce tedy může překladač zpracovávat zcela libovolným způsobem, dokonce nemusí docházet na příslušným místě ke skutečnému volání funkce, což umožňuje vyšší míru manipulace s kódem a tím pádem i potenciálně kvalitnější optimalizace.
  • Ne vždy se předefinování funkce v Common Lispu projeví, neprojeví se u inlinovaných funkcí.

Každopádně možnost dynamického předefinování funkcí je velmi důležitá optimalizace práce programátora. Nemusíte kvůli změně jednoho volání v programu překládat celý programový celek znovu, stačí v editoru zavolat příkaz předání nové definice změněné funkce překladači.

Optimalizace: Překlad do strojového kódu obvykle nic nemění na interaktivitě prostředí. I překladače, které generují pouze strojový kód, fungují za normálních okolností plně dynamicky a interaktivně.

Typování

Common Lisp je obecně jazykem s dynamickým typováním, tj. každá proměnná může obecně nabývat hodnoty libovolného typu a informace o typu je součástí hodnoty proměnné. Ve skutečnosti tomu ovšem takto vždy být nemusí, a to ze dvou důvodů:

  • Typ proměnné nebo funkce je deklarován programátorem ve zdrojovém kódu.
  • Typ lokální proměnné je možné určit z kontextu.

Občasné deklarace typů ve spolupráci s automatickým odvozováním typů lokálních proměnných překladačem je velmi mocný optimalizační prostředek. Rychlost kódu je typicky ovlivněna cykly, tj. lokálními částmi kódu. Lze-li v takových místech odvodit typy proměnných automaticky nebo s částečnou asistencí programátora, dochází ke skloubení výhod dynamicky a staticky typovaných jazyků.

Optimalizace: Programátor uvádí typy proměnných jen v místech, kde je potřeba překladači napovědět nebo kde mu záleží na kontrole dat (assertions). Kde je to možné, tam si překladač může odvodit typ sám a tudíž automaticky generovat efektivní kód. Kvalitně optimalizující překladač přitom dokáže upozornit na místa, kde mu informace o typu chybí. Tím se ušetří práce programátora oproti jazykům s povinným typováním (jako je C, C++ nebo Java, kde je zbytečně nutné uvádět informaci o typu skoro všude) a přitom lze generovat efektivnější kód než v případě jazyků s výhradně dynamickým typováním (jako je Perl nebo Python).

Schopností automatického typování ovšem nedisponuje každý překladač. Překladač dokonce smí veškeré typové deklarace, stejně jako většinu ostatních deklarací, kompletně ignorovat. Cílem standardu je definovat přenositelný jazyk, avšak bez kladení zbytečných nároků na své implementace.

Nejen proto je třeba Common Lisp nezaměňovat se silně typovanými jazyky, a to i přesto, že občas poskytuje lepší typovou kontrolu než jazyky, u nichž je silné typování zdůrazňováno. Kladete-li důraz na bezpečnost typování, musíte použít některý ze skutečných silně typovaných jazyků, jako je například Ada nebo Mercury.

Garbage collection

Garbage collection je přímo legendárním pojmem v debatách o rychlosti běhu kódu. Ještě před nedávnem bylo její používání častým námětem připomínek na adresu "pomalosti kódu", povětšinou nepodložených ničím jiným než naprostou neznalostí problematiky.

Předně je potřeba si uvědomit, že nikomu nic nebrání programovat v Common Lispu stejným způsobem jako v jazyce C. Tj. alokovat si jeden velký úsek paměti a "ručně" provádět jeho správu. Pak je práce garbage collectoru nulová a žádné zpomalení tudíž nemůže působit. Využití garbage collection je tedy volitelné.

Pro použití garbage collection existují v zásadě dva důvody:

  • Chcete si ušetřit spoustu programátorské práce související s ruční správou paměti.
  • Dobrý garbage collector může fungovat efektivněji než ruční správa paměti napsaná programátorem, který problematice správy paměti dostatečně dobře a do hloubky nerozumí. Uvolňování bloků paměti při garbage collection může být například prováděno v jednom větším kroku místo několika malých a může mít lepší lokalitu.

Využití garbage collectoru obvykle vede jednak k velké úspoře programátorské práce už při psaní samotného kódu, a jednak k zefektivnění výsledného kódu. Postupy provádění garbage collection jsou dnes mnohem rafinovanější než byly v začátcích používání této techniky a až na výjimečné situace je časová režie garbage collectoru víceméně zanedbatelná. Hůře je na tom garbage collection s pamětí, protože na rozdíl od okamžité dealokace dat se v paměti skoro vždy nachází nějaké to smetí, až do chvíle příštího sběru. To je však vyváženo tím, že v případě systémů s rozumným garbage collectorem je pojem "memory leak" záležitostí známou jen z doslechu od cizinců. Stejně tak se vám nemůže stát, že se něco bude v automaticky spravované oblasti paměti odkazovat na již uvolněná data, s dobře známými následky. Pokud by pak kvůli garbage collection mělo dojít ke skutečným výkonnostním problémům, což se teoreticky může stát, pracuje-li program s velkým množstvím datových objektů silně dynamického charakteru, je možno zabránit přítomnosti přílišného množství smetí umístěním kritické části dat do ručně spravovaného pole.

Optimalizace: Garbage collection ušetří spoustu programátorské práce. Ušetřené prostředky lze mimo jiné využít na optimalizaci použitých algoritmů a technik, povětšinou vedoucích k optimalizacím programu účinnějších než veškeré optimalizační metody běžných překladačů.

Optimalizace: V mnoha programech garbage collection omezí spotřebu paměti programu na konkrétní limit, na rozdíl od programátorských prostředí umožňujících úniky paměti (pamatujete si ještě na starší verze Netscape?).

Samozřejmě je nutné mít na paměti, že nic není odolné proti dostatečně hloupým postupům a chybám. Ani garbage collection nezamezí ničím neomezenému růstu zásobníku, do kterého se jen přidává a nic se z něj neodebírá.

Nastavení preferencí optimalizace

Některé optimalizace jdou proti sobě. Často máte například na výběr mezi zvýšením rychlosti prováděného kódu a zmenšením jeho velikosti, nemůžete mít obojí, typicky při expanzi cyklů (loop unrolling). Zatímco u mnoha překladačů máte na výběr mezi prostým "optimalizovat" nebo "neoptimalizovat" či mezi několika sekvenčně vzrůstajícími stupni optimalizace, Common Lisp umožňuje volný výběr z několika parametrů. Deklarace optimalizace jsou přitom opět součástí standardu jazyka, nikoliv jen stanoveny nějakým konkrétním překladačem.

Standard Common Lispu definuje pět parametrů ovlivňujících výslednou optimalizaci kódu: speed, space, safety, debug, compilation-speed. Každému z těchto parametrů lze přiřadit jeden ze čtyř stupňů důležitosti, přičemž standard nestanovuje jejich přesnou interpretaci, ta závisí čistě na konkrétním překladači (může je i zcela ignorovat).

Parametry speed a space umožňují preferovat rychlost a velikost výsledného kódu. Například při nízké hodnotě speed a vysoké hodnotě space může překladač generovat byte kód, zatímco v opačném případě strojový kód. Nebo může vzájemná hodnota těchto parametrů určovat, do jaké míry se má provádět expanze cyklů.

Parametr safety říká, nakolik má být generovaný kód zabezpečený proti běžným programátorským chybám, jako je například překročení hranic pole nebo přiřazení hodnoty do proměnné s odlišným deklarovaným typem. U většiny překladačů jiných programovacích jazyků nemáte na výběr a musíte se smířit buď se vždy přítomnou (kód zpomalující a zvětšující) kontrolou, nebo naopak s tím, že není prováděna žádná kontrola, nebo s kontrolou přítomnou v případě použití externích nástrojů. V Common Lispu si stačí jen nastavit příslušnou optimalizaci.

Konečně parametr debug definuje, jaké mají být v kódu ponechány ladící informace, a parametr compilation-speed určuje, jak moc vám záleží na rychlosti kompilace.

Optimalizace: Optimalizaci lze optimalizovat s ohledem na konkrétní potřeby programu.

Velmi zajímavou vlastností těchto parametrů, jinde málokdy viděnou, je možnost definovat je nejen na úrovni celého překladu nebo celého zdrojového souboru, nýbrž i na úrovni jednotlivé funkce nebo bloku funkce. Máte-li tedy v programu jediné místo kritické z hlediska rychlosti, nastavíte mu po odladění parametr speed na nejvyšší hodnotu a ostatní parametry na hodnoty nejnižší, aniž by to ovlivnilo optimalizace kteréhokoliv jiného kódu.

Optimalizace: Optimalizaci lze optimalizovat přesně v místech, kde je to žádoucí.

Common lispový program také jen málokdy specifikuje úroveň optimalizace pro program jako celek přímo. To je ponecháno na uživateli, který si může veškeré výše uvedené optimalizační parametry před překladem nastavit dle svého gusta. Nemusí kvůli tomu editovat žádné zdrojové texty ani žádné makefile.

Optimalizace: Optimalizaci si uživatel může optimalizovat s ohledem na své potřeby.

Pro úplnost dodejme, že mezi optimalizační parametry podobného druhu patří ještě možnost zažádat si o inlinování konkrétní funkce, což je technika dobře známá například v případě C++. Již méně obvyklou je možnost zažádat si naopak o neinlinování konkrétní funkce.

Překlad kódu

U staticky překládaných jazyků lze kód překládat jen v podobě zdrojového souboru a k překladu musí dojít za normálních okolností ještě před spuštěním výsledného programu. Dynamické jazyky k tomu přidávají konstrukce load a eval, umožňující vyhodnocení kódu programovacího jazyka za běhu. Common Lisp kromě toho nabízí ještě dva další důležité mechanismy: Překladová makra a kompilaci za běhu.

Překladová makra (compiler macros) jsou makra expandovaná jen v době překladu. Jedná se o rozšíření mechanismu maker, spočívající v zastínění jména funkce nebo makra v určité fázi překladu. Tento prostředek umožňuje provádět nad kódem "vnější" transformace, bez zásahu do samotného kódu. Využití se nabízí například pro optimalizaci některých aritmetických konstrukcí v programech provádějících numerické výpočty.

Optimalizace: V některých situacích lze pomocí překladových maker automaticky optimalizovat konstrukce, které překladač neumí optimalizovat sám.

Kompilace za běhu spočívá v možnosti zkompilovat během provádění programu libovolnou, třeba až v daném okamžiku dynamicky zkonstruovanou funkci. Programátor tak získává možnost ve svém programu dynamicky generovat kód ve stejné kvalitě jako statický kód, a to bez nutnosti používání dočasných souborů (jako je tomu v případě postupu define--save--compile-file--load). Jako typické smysluplné využití této možnosti se nabízí zpracování uživatelem zadávaných regulárních výrazů -- pro každý regulární výraz můžete vytvořit plně optimalizovaný program provádějící jeho porovnávání, místo obvyklé interpretace byte kódu zpracovaného regulárního výrazu.

Optimalizace: Překlad kódu dynamicky vytvořeného za běhu programu je stejně kvalitní jako překlad statického kódu.

Jsou programy v Common Lispu rychlé nebo pomalé?

Common Lisp disponuje celou řadou optimalizačních prostředků. V článku bylo uvedeno několik optimalizací, které v jiných prostředích běžně nenalezneme. Po stránce vlastností jazyka má Common Lisp díky vyšší abstrakci jazyka a uvedeným rysům předpoklady generovat efektivnější kód než jazyky nižší úrovně, jako je například C.

Praktická zkušenost se svobodnými common lispovými překladači ukazuje, že rychlost provádění programů zkompilovaných do strojového kódu je o něco nižší, než provádění analogického kódu zkompilovaného gcc (které asi lze považovat za jeden z nejlépe optimalizujících svobodných překladačů). Důvodem je to, že v případě gcc je low-level optimalizacím výsledného kódu věnováno mnohonásobně větší než v případě svobodných common lispových překladačů. Rozdíl však není příliš dramatický a praktickou roli hraje především ve výpočetně náročných aplikacích. Záleží také hlavně na aplikaci, aplikace využívající multimediálních instrukcí intelovských procesorů budou určitě rychlejší, bude-li je překládat gcc, aplikace dynamického charakteru s vysokou úrovní abstrakce kódu zase mohou běžet rychleji při použití Common Lispu.

V případě dynamických jazyků, jako je třeba Python nebo Perl, se často argumentuje, že na rychlosti kódu nezáleží, protože časově kritické části, kterých v kódu nebývá mnoho, lze napsat jako moduly v jazyce C (stejný přístup používá populární common lispový překladač Clisp). Tento argument je v zásadě správný, naráží však na určitý praktický problém, že se u komplikovanějších systémů stává programování v C nezbytností, se všemi důsledky z toho plynoucími. Těmi jsou zejména složitý kód, nedostupnost některých rysů jazyka pro takový kód, jeho nestabilita (segmentation fault v Pythonu může programátora přivádět do stavu blízkého zoufalství) a nemožnost ladění s pomocí mocných nástrojů pro daný jazyk dostupných. Proto bývá občas výhodnější místo investice do přepisování kódu do C raději investovat do silnějšího hardwaru. V případě kvalitního překladu, který je podmíněn dostatečnými optimalizačními rysy jazyka, nemusíte investovat ani do dodatečné programátorské práce ani do hardwaru, výsledný kód je sám o sobě dostatečně dobrý. I v Common Lispu se občas využívají knihovny v C, nikoliv ovšem z důvodu potřeby vyšší rychlosti běhu kódu, nýbrž prostě z důvodu využití stávajícího knihovny bez nutnosti psaní její lispové varianty, smíří-li se programátor s výše uvedenými nedostatky implikovanými takovým postupem.

Odkazy

Autor: Milan Zamazal, 19. 01. 2004, 00:00
Sekce Programování, Komentářů: 9
Průměrné hodnocení: 2,88

o Poslat e-mailem
o Tisk článku
o Uložit do profilu


 Přispějte nám




Líbil se Vám tento článek? Můžete ho ocenit zavoláním na tel. číslo 906 460 134.
Cena hovoru za 1 minutu je 46 Kč.





 Hodnocení článku




Článek hodnotím jako:  [1] výborný   [2] dobrý   [3] průměr   [4] špatný   [5] hrůza  





 Komentáře




--

Milan Zamazal, 29. 03. 2004 08:30
Re: Rychlost lispu












--

Milan Zamazal, 27. 03. 2004 21:06
Re: Rychlost lispu












--

 - , 26. 03. 2004 16:59
Rychlost lispu












--

Milan Zamazal, 19. 01. 2004 15:31
Re: Literatura?












--

Milan Zamazal, 19. 01. 2004 15:22
Re: NEJLEPSI CLANEK!












--

Vitas, 19. 01. 2004 14:52
Re: Literatura?












--

lzap, 19. 01. 2004 14:09
NEJLEPSI CLANEK!












--

Milan Zamazal, 19. 01. 2004 09:12
Re: Literatura?












--

Petr B., 19. 01. 2004 07:56
Literatura?















PŘIDAT KOMENTÁŘ ZOBRAZ VŠE >>










2002 © Impossible, s.r.o.   >> Kontaktujte redakci >> Právní upozornění >> Reklama