25. března 2017

Clojure concurrency: Vars

Významnou vlastností Clojure jsou neměnitelné datové struktury. Je to taková dvojsečná vlastnost (i když benefity výrazně převažují). Na jednu stranu to vývoj zjednodušuje, protože se nemusíme bát, že se nám data změní pod rukama.

Nadruhou stranu vyvstává otázka, jak s neměnitelnými daty pracovat - nic v našem světě není neměnné (a všechno jednou pomine). Jak tedy Clojure řeší změnu stavu a s tím související konkurenci?

K dispozici jsou čtyři mechanizmy, jak měnit stav:
  • Vars jako globální úložiště, pro eventuální per-thread změny.
  • Atoms pro synchronní, nekoordinované změny.
  • Refs pro synchronní, v transakci koordinované změny.
  • Agents pro asynchronní, nekoordinované změny.
Postupně bych se chtěl podívat na všechny způsoby, ale dnes začneme tím nejjednodušším, čemu se žádný začátečník v Clojure nevyhne.

Vars

Var je způsob, jakým Clojure odkazuje na úložiště. Toto úložiště obsahuje "standardní", neměnná data. Var, ale můžeme dočasně přesměrovat na jiné úložiště. Podstatnou vlastností je, že toto dočasné přesměrování - binding - je vidět jenom v rámci aktuálního vlákna, ostatní vlákna vidí pořád původní hodnotu.

Statické Vars

Klasické Var se vytvoří speciálním formem def: (def x 42). Takto definováno, je Var statické - pokud bychom ho chtěli svázat s jiným úložištěm, vyhodí Clojure výjimku IllegalStateException.


Dynamické Vars

Pokud chceme, aby Var ukazovalo na jiné úložiště, musíme ho explicitně definovat jako dynamické pomocí instrukce ^:dynamic. Samotné přesměrování se provádí makrem binding. Po dobu trvání bloku binding směřuje Var na nové úložiště, aby se po jeho skončení vrátilo ke své původní hodnotě.

Dle konvence se dynamické Vars uzavírají do *earmuffs*. Označují se tak věci, určené pro re-binding.


Vars jsou globální

Vars jsou globální - viditelné pro všechny thready. Pokud tedy vytvoříme Var v jiném vlákně, je dosažitelné také ze všech ostatních vláken.

V následujícím příkladu vytvoříme Var v jiném vlákně pomocí makra future:


Namespace

V rámci namespace, v němž byly vytvořeny, jsou Vars přístupné svým názvem. Pokud se přepneme do jiného namespacu, je potřeba na Var odkazovat plně kvalifikovaným názvem, nebo ho "naimportovat" z původního namespace pomocí funkce refer.


Funkce jsou také Vars

Ve Vars se neukládají jenom data, ale také funkce. Všechno výše napsané tedy platí pro funkce úplně stejně, včetně toho, že je můžeme dynamicky re-bindovat.

To může být zajímavý mechanismus, jak v runtimu dynamicky měnit chování funkcí. Nicméně, užívejte s mírou - jazyk to umožňuje, ale je to výjmečné řešení.


A kde je ta konkurence?

Se samotnými Vars si moc konkurentního programování neužijeme. Je to ale základní stavební kámen, od kterého se odvíjejí ostatní způsoby. Konec konců, všechny v úvodu zmíněné mechanizmy - Atomy, Refs a Agenti - jsou ve výsledku uloženy ve Vars.

Související články

  • TBD: Clojure concurrency: Atoms
  • TBD: Clojure concurrency: Refs
  • TBD: Clojure concurrency: Agents

Starší související články

18. března 2017

Catalanova čísla a syntax highlighting

Je to téměř 5 let, co jsem naposled napsal něco na tento blog. Ale doufám, že se to teď změní - moje láska ke Clojure opět propukla s neztenčenou silou a tak snad ponese nějaké užitečné ovoce.

Chvilku ale potrvá, než uvedu blog do použitelného stavu, takže začnu takovým zahřívacím tématem. Tedy, dvěma tématy - sice to není úplně fér, ale vrazil jsem do titulku dva nesouvisející motivy.

Syntax highlighting 3.0

Když jsem s Clojure před šesti lety začínal, bylo ve verzi 1.2 a jeho podpora v různých nástrojích byla nízká, nebo žádná. Jednu z věcí, které jsem tehdy řešil, bylo jak zobrazit na blogu syntax highlighting.

Moje první volba padla na tehdy všudypřítomný SyntaxHighlighter. Musel jsem použít jakýsi externí Clojure brush, protože SyntaxHighlighter dodnes nemá nativní podporu Clojure.

S výsledkem jsem nebyl spokojen, takže jsem po čase zvolil nové řešení - jako letitý uživatel famózního editoru Vim, jsem se rozhodl pro trochu ruční práce a zaangažoval vimovskou funkci :TOhtml. S tou jsem maximálně spokojen a používám ji i na svém druhém blogu SoftWare Samuraj. Přesto jsem se rozhodl potřetí pro změnu syntax highlightingu.

Ten třetí důvod má konsekvence s oživením blogu. Aniž bych si tady vylíval srdíčko, jeden z důsledků mých aktuálních rozhodnutí je, vybudovat si na svém GitHubu jakési Clojure portfolio (už jsem o tom kdysi psal).

Volba GitHubu pro mne nebyla úplně přímočará - nejsem "git guy" a pokud můžu, preferuji Mercurial. Pravdou ale je, že veškerá Clojure komunita je GitHubu, tak proč se tomu vzpírat. No, a když GitHub, tak Gist, to dá rozum.

Catalanova čísla

V rámci svého Clojure-zmrtvýchvstání jsem procházel své staré Clojure kódy a narazil jsem na jeden, který se mi líbil - funkce pro výpočet Catalanových čísel. Pikantní je, že si po těch pěti letech nepamatuju, proč jsem to napsal, nicméně funkce se mi líbily natolik, že jsem se rozhodl se o ně - v rámci zahřátí na provozní teplotu - podělit.

Catalanova čísla jsou sekvencí přirozených čísel, která má zajímavé využití v kombinatorice - binární stromy, průchod mřížkou(?), rozdělení polygonu na trojúhelníky ad. Sekvence je definována následujícím vztahem:


Pokud, tak jako já, nejste úplně kovaní v matematice, tak chviličku googlování potrvá, než zjistíte, že pro implementaci tohoto vzorečku budete potřebovat kombinační číslo (binomial coefficient) a tím pádem faktoriál. Pak už je jednoduché poskládat tyto základní funkce do sebe, jako matrojšku:


Když už jsem se v tom tak vrtal, říkal jsem si: nedá se to udělat nějak jednodušeji, efektněji, víc "Clojure"? A dá. Jen je potřeba vyjít z jiného vzorečku, který definuje Catalanova čísla rekurzivně:
Při použití posledního vzorečku nám tak vyjde pěkná Clojure rekurze. Klíčová slova jsou speciální operátory loop a recur:


GitHub project

Pokud si chcete pohrát s Catalanovými čísly trochu víc, anebo dostat malý bonus navíc, podívejte se na můj projekt na GitHubu:
Navíc dostanete Leiningen projekt, testy v Midje a lazy sekvenci Catalanových čísel.

Související články