JupyterLite: nová alternativní architektura Jupyter Notebooku

20. 7. 2021
Doba čtení: 29 minut

Sdílet

 Autor: JupyterLite project
V dnešním článku se seznámíme se zajímavým projektem nazvaným JupyterLite. Jedná se o alternativu ke známému Jupyter Notebooku, která však běží kompletně v prohlížeči a na straně serveru vyžaduje jen poskytnutí statického obsahu.

Obsah

1. JupyterLite – nová alternativní architektura Jupyter Notebooku

2. Architektura klasického Jupyter Notebooku

3. Architektura projektu JupyterLite

4. Ekosystém Pythonu běžící v prohlížeči nad Web Storage

5. Projekt Pyodide

6. Praktická část – příprava na instalaci projektu JupyterLite

7. Instalace potřebných balíčků

8. Sestavení statického webu s JupyterLite

9. Zobrazení uživatelského rozhraní JupyterLite v prohlížeči

10. Sledování interní činnosti projektu JupyterLite

11. Server s vlastními diáři

12. Knihovny dostupné v základní instalaci projektu JupyterLite

13. NumPy

14. Matplotlib

15. Rychlost výpočtů v porovnání s nativním Jupyter Notebookem

16. Další možnosti projektu JupyterLite

17. Technologie WebAssembly (WASM)

18. Odkazy na články o Jupyter Notebooku

19. Odkazy na články a videa s tématem technologie WebAssembly

20. Odkazy na Internetu

1. JupyterLite – nová alternativní architektura Jupyter Notebooku

S projektem Jupyter Notebook jsme se již na stránkách Roota několikrát setkali. Ukázali jsme si přitom jak práci s Pythonem, resp. přesněji řečeno s kernelem poskytujícím prostředí CPythonu, tak i s využitím Jupyter Notebooku společně s dalšími programovacími jazyky – konkrétně s Clojure, jazykem R, jazykem Go a v neposlední řadě taktéž s jazykem Hy.

Obrázek 1: Základní informace o projektu JupyterLite zobrazené přímo ve webovém prostředí.

Jednotlivé varianty se přitom odlišovaly „pouze“ výměnou kernelu, zatímco architektura Jupyter Notebooku zůstala stále stejná: kernel běží na straně serveru a o interakci s uživatelem se stará webová část. Toto řešení ovšem vyžaduje práci na straně serveru, zejména zabezpečení, nutnost zajistit dostatečný výpočetní výkon pro celou třídu (při výuce) atd. Existuje však i alternativní řešení, které spočívá v tom, že veškeré výpočty budou probíhat přímo na straně klienta, konkrétně v jeho webovém prohlížeči. A právě toto řešení je implementováno v projektu JupyterLite.

Obrázek 2: Úvodní obrazovka projektu JupyterLite při přístupu ke statickému obsahu z jiného počítače.

2. Architektura klasického Jupyter Notebooku

Připomeňme si ve stručnosti, jak vlastně vypadá architektura systému Jupyter Notebook; posléze si popíšeme odlišnosti mezi klasickým projektem Jupyter a Jupyterem Lite. Nástroj Jupyter Notebook je založen na klasické technologii klient-server, kde klientem je webový prohlížeč spuštěný u uživatele (či uživatelů) a serverem je Jupyter s přidaným modulem (takzvaným kernelem) pro zvolený programovací jazyk nebo jazyky. Výraz, popř. blok výrazů představujících programový kód napsaný ve zvoleném programovacím jazyce, je po stlačení klávesové zkratky Shift+Enter (v prostředí webového prohlížeče) přenesen na server, kde je zpracován a výsledek je poslán zpět do prohlížeče. Prakticky veškeré výpočty jsou tedy prováděny na straně serveru, který pochopitelně může běžet lokálně.

Obrázek 3: Nástroj Gorilla REPL obsahuje podporu pro doplňování názvů funkcí a maker společně se zobrazením nápovědy (programové dokumentace). Jedná se o nástroj založený na stejném paradigmatu jako dnes popisovaný Jupyter Notebook resp. JupyterLite, ovšem Gorilla REPL je primárně určen pro programovací jazyk Clojure zatímco Jupyter Notebook je více univerzální (původně vznikl pro Python, dnes podporuje cca třicet dalších jazyků).

JavaScriptový kód na straně prohlížeče zajistí interpretaci získaných výsledků a jejich zařazení na správné místo do dynamické webové stránky (jedná se vlastně o variantu na dnes tak populární SPA – Single-Page Application se všemi přednostmi a pochopitelně i některými zápory, které toto řešení přináší). Výsledky poslané serverem na klienta mohou být ve skutečnosti různého typu; typicky se jedná o fragment HTML (tabulky atd.), obrázek typu SVG (diagram, graf, histogram), rastrový obrázek (graf získaný například ze systému R), vzorec vykreslený z TeXového či LaTeXového zdrojového kódu, animace či video (různé formáty) apod. Samotná architektura nástroje Jupyter je přitom do značné míry otevřená a poměrně snadno rozšiřitelná, což znamená, že je v případě potřeby možné přidat například další typy grafů apod.

Poznámka: existují i podobně koncipované projekty. Na stránkách Rootu již vyšel článek o projektu Gorilla REPL, který je určen pro programovací jazyk Clojure a princip diáře (notebooku) nalezneme u mnohých „webových IDE“, kterých dnes existuje nepřeberné množství.

Obrázek 4: Dalším podobným projektem je R Markdown notebook, který je (jak již jeho název naznačuje) určený pro jazyk R zkombinovaný s Markdownem.
Zdroj: dokumentace k projektu dostupná na https://bookdown.org/yihu­i/rmarkdown/notebook.html

Jak jsme si již řekli v úvodní kapitole, vznikl projekt Jupyter Notebook rozšířením původního projektu nazvaného IPython Notebooks. V případě Jupyter Notebooku musely být provedeny některé změny v celé architektuře, a to především z toho důvodu, aby bylo možné podporovat různé programovací jazyky (nikoli pouze Python), další typy specializovaných kernelů apod. Základem je přitom stále IPython Kernel, který přijímá zprávy (příkazy, které se mají vykonat) přes ØMQ, vykonává tyto příkazy a výsledky posílá zpět přes ØMQ (povšimněte si, že v tomto případě samotný kernel vůbec nezajímá, kdo příkazy posílal):

Obrázek 5: IPython Kernel a jeho navázání na ØMQ (popř. alternativní přístup přes standardní vstupně-výstupní operace přístupné přes terminál).
Zdroj: How IPython and Jupyter Notebook work

IPython Kernel podporuje – což asi není při přečtení jeho jména velkým překvapením – programovací jazyk Python. Ovšem do Jupyter Notebooku lze přidat i další kernely (takzvané nativní kernely), které mohou podporovat další programovací jazyky. Alternativně není nutné vytvářet celý nový kernel (což může být komplikované kvůli nutnosti napojení na ØMQ atd.), ale lze použít přímo IPython Kernel tak, aby volal příkazy interpretru jiného programovacího jazyka. Teoreticky se sice nejedná o nejefektivnější řešení, ovšem musíme si uvědomit, že spouštěny budou příkazy zapisované přímo uživatelem a že tedy uživatel je „úzkým hrdlem“, ne výkonnost jednoho interpretru volaného z interpretru jiného:

Obrázek 6: Dva způsoby, jakými je možné Jupyter rozšířit o další jazyky: nepřímo přes IPython a přímo nativním kernelem.
Zdroj: How IPython and Jupyter Notebook work

Máme tedy dva moduly – webové rozhraní (webový prohlížeč s JSA) a kernel či kernely. Tyto dva moduly nejsou propojeny přímo, protože mezi nimi leží Notebook server. Ten z jedné strany komunikuje s webovým rozhraním přes HTTP a WebSockety a ze strany druhé s kernelem/kernely přes ØMQ. Navíc server udržuje stav vlastního diáře. Toto řešení je snadno rozšiřitelné, může být provozováno na jednom stroji (což si ukážeme dále) či v „cloudu“ atd. Taktéž umožňuje spolupráci na jednom diáři, prezentaci živých výsledků apod., což je naznačeno na dalším obrázku:

Obrázek 7: Připojení vlastního uživatelského rozhraní (založeného na webovém klientu) k serveru a propojení serveru s kernelem (kernely).
Zdroj: How IPython and Jupyter Notebook work

3. Architektura projektu JupyterLite

Projekt JupyterLite se z pohledu celkové architektury odlišuje od klasického Jupyter Notebooku. Namísto řešení typu klient-server, kdy jsou prakticky veškeré výpočty prováděny na straně serveru (který tak musí mít nainstalovány všechny potřebné kernely i příslušné knihovny), se v případě JupyterLite přenáší výkonná část (kernely, příslušné interpretry a knihovny) na stranu klienta. Ovšem jak toho lze dosáhnout, když klientem je v tomto případě webový prohlížeč? Jak kernely, tak i podporované interpretry (zejména Pythonu) je nutné upravit takovým způsobem, aby běžely přímo ve webovém prohlížeči. K vyřešení tohoto úkolu dnes existuje hned několik technologií:

  1. Využití takzvaných transpilerů (transpřekladačů, též transcompilers, source-to-source compilers), kdy cílem je JavaScript. Touto problematikou jsme se již na stránkách Rootu zabývali, a to dokonce několikrát. Transpřekladače jsou nástroje sloužící pro překlad algoritmů zapsaných v nějakém zdrojovém programovacím jazyce do zvoleného cílového jazyka (ovšem nikoli do nativního kódu či bajtkódu, to je totiž role běžných překladačů). Připomeňme si například projekty ClojureScript (transpřekladač Clojure → JavaScript), lua2js (transpřekladač Lua → opět JavaScript), Wisp (programovací jazyk podobný Clojure, opět překládaný na pozadí do JavaScriptu) i transpřekladač Coconut (ten ovšem nemá s JavaScriptem nic společného).
  2. Podobná technologie provádějící ovšem překlad do asm.js, tj. do striktně definované podmnožiny JavaScriptu. Podmnožina datových typů, konstrukcí jazyka, způsobů využití paměti (vše prováděno v předalokovaných polích) atd. je zvolena s ohledem na co největší výpočetní výkon výsledného skriptu – tj. jedná se o optimalizaci založenou na znalostech činnosti současných implementací JavaScriptu (V8 atd.).
  3. Reimplementace kernelu, interpretrů i knihoven v JavaScriptu. Příkladem využití může být projekt Brython, tj. reimplementace Pythonu pro webové prohlížeče. Ovšem reimplementace všech potřebných knihoven by byla dosti nepraktická, nehledě na problémy se zpětnou kompatibilitou atd..
  4. Lze použít i nástroj Emscripten umožňující překlad zdrojového kódu z libovolného jazyka podporovaného LLVM (Rust, C, C++, Objective C, D, Ada, Fortran atd.) do JavaScriptu nebo do WebAssembly (WASM). Právě projekt Emscripten do značné míry usnadnil další způsob zajištění běhu programů napsaných v různých programovacích jazycích ve webovém prohlížeči. Pokud je totiž možné přeložit jakýkoli program napsaný v jazycích C či C++ do JavaScriptu či WebAssembly (samozřejmě za předpokladu, že se vhodným způsobem budou emulovat použité knihovní funkce), proč by nebylo možné přeložit „pro web“ celý virtuální stroj používaný daným programovacím jazykem? Samozřejmě to možné je, a to zejména v těch případech, kdy je překládaný virtuální stroj (alespoň z dnešního pohledu) malý, což je příklad VM pro jazyk Lua, tak i například poněkud většího virtuálního stroje Pythonu (.NET resp. CLR či Java VM už je pochopitelně mnohem těžší oříšek).

4. Ekosystém Pythonu běžící v prohlížeči nad Web Storage

Konkrétně v případě projektu JupyterLite byla zvolena poslední zmíněná možnost, tedy překlad CPythonu (standardního interpretru Pythonu) i některých důležitých nativních knihoven (část NumPy) do WebAssembly (viz též sedmnáctou kapitolu). To však není vše, protože běžný interpret Pythonu používá příkazový řádek, dokáže pracovat se souborovým systémem atd. – tedy s technologiemi, které ve webovém prohlížeči buď v původní formě vlastně vůbec neexistují (příkazový řádek) nebo je naopak nechceme kvůli sandboxingu přímo využívat (přístup na souborový systém). Odstínění od těchto technologií je taktéž zajištěno, a to v rámci dále zmíněného projektu Pyodide. Výsledkem jsou binární soubory (pro WebAssembly), jejichž velikost je relativně velká – cca 22 MB pro Python a 7 MB pro NumPy. Tyto soubory, jak ostatně uvidíme dále, jsou staženy pouze jedenkrát, při prvním spuštění JupyterLite; posléze jsou již využity jejich cachované verze.

Jak je však zajištěna práce s vlastními diáři (notebook), když JupyterLite nemůže přímo přistupovat na souborový systém. Pro uložení všech dat se používá web storage (více informací je dostupných na stránce https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API) poskytovaná přímo webovým prohlížečem. Stále je pochopitelně možné diáře exportovat do běžných souborů a – jak uvidíme dále – lze dokonce vytvořit statický webový obsah s diáři, které si mohou uživatelé otevřít a lokálně upravit. Původní obsah diáře přitom zůstane zachován, což je téměř ideální situace například pro různá školení či prezentace.

Z pohledu uživatelů se tedy JupyterLite chová jako interaktivní webová aplikace, která si „pamatuje“ změny provedené v jednotlivých diářích – ve skutečnosti jsou tyto změny uloženy lokálně v paměti prohlížeče. A z pohledu administrátorů není JupyterLite nic jiného, než statický web, který na straně serveru vyžaduje libovolný web server (nginx, Apache HTTP atd.), nebo je dokonce možné celý web zveřejnit přes github.io, wiki či podobné nástroje. Pro sestavení tohoto statického webu se používají pomocné nástroje zmíněné v dalších kapitolách.

5. Projekt Pyodide

Nástroj JupyterLite je primárně postaven na projektu nazvaném Pyodide. Jedná se v prvé řadě o upravený překlad celého standardního Pythonu (konkrétně Pythonu 3.9) nikoli do nativního kódu spustitelného přímo z příkazové řádky, ale do WebAssembly, což znamená, že interpret Pythonu, resp. přesněji řečeno programů napsaných pro Python, lze spustit přímo z webového prohlížeče, a to dokonce bez nutnosti mít Python lokálně nainstalovaný – musíme mít pouze k dispozici vhodný webový server, stránky na github.io atd. Kromě toho je součástí projektu Pyodide i poměrně velké množství důležitých balíčků používaných ve vědeckotechnických výpočtech, zpracování numerických dat, statistických výpočtech, strojovém učení atd. Primárně se jedná o balíčky NumPy, Pandas, Matplotlib, SciPy a taktéž scikit-learn; s mnohými z nich jsme se ostatně na stránkách Roota již setkali. Seznam všech balíčků použitých v aktuální verzi Pyodide nalezneme na adrese https://github.com/pyodide/py­odide/tree/main/packages:

CLAPACK Jinja2 MarkupSafe Pygments
asciitree astropy atomicwrites attrs
autograd beautifulsoup4 biopython bleach
bokeh cloudpickle cssselect cycler
cytoolz decorator distlib docutils
freesasa future glpk html5lib
imageio jedi joblib kiwisolver
libiconv libxml libxslt libyaml
lxml matplotlib micropip mne
more-itertools mpmath msgpack networkx
nlopt nltk nose numcodecs
numpy optlang packaging pandas
parso patsy pillow pluggy
py pyodide-interrupts pyparsing pyrtl
pytest python-dateutil python-sat pytz
pywavelets pyyaml regex retrying
scikit-image scikit-learn scipy setuptools
six soupsieve statsmodels swiglpk
sympy toolz traits typing-extensions
uncertainties webencodings xlrd yt
zarr zlib    
Poznámka: s architekturou projektu Pyodide se blíže seznámíme v samostatném článku.

6. Praktická část – příprava na instalaci projektu JupyterLite

V praktické části dnešního článku si nejdříve ukážeme, jakým způsobem se nainstalují pomocné nástroje, které dokážou sestavit statický obsah webu s nástrojem (či možná lépe řečeno prostředím) JupyterLite a popř. i s předpřipravenými diáři neboli notebooky. Všechny přípravné operace budou prováděny na Fedoře 33 ve variantě server; pouze se doinstalovalo několik podpůrných balíčků – tar, git či wget. Konfigurace použitého serveru je následující (pro úplnost uvádím i příkazy, kterými se příslušné informace získaly):

$ cat /etc/fedora-release
 
Fedora release 33 (Thirty Three)
$ uname -a
 
Linux kvm-01-guest04.lab.eng.brq.redhat.com 5.12.15-200.fc33.x86_64 #1 SMP Wed Jul 7 19:56:49 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
$ python --version
 
Python 3.9.6
$ pip --version
 
pip 20.2.2 from /usr/lib/python3.9/site-packages/pip (python 3.9)

7. Instalace potřebných balíčků

Jak jsme si již řekli v předchozím textu, používá se pro sestavení statického obsahu webu podpůrný nástroj. Ten je možné nainstalovat přímo z PyPi, a to konkrétně následujícím příkazem:

$ pip install --user --pre jupyterlite
 
Collecting jupyterlite
  Downloading jupyterlite-0.1.0a5-py3-none-any.whl (20.1 MB)
     |████████████████████████████████| 20.1 MB 2.6 MB/s
Collecting doit
  Downloading doit-0.33.1-py3-none-any.whl (84 kB)
     |████████████████████████████████| 84 kB 4.7 MB/s
Collecting jupyter_core>=4.7
  Downloading jupyter_core-4.7.1-py3-none-any.whl (82 kB)
     |████████████████████████████████| 82 kB 1.5 MB/s
Collecting entrypoints
  Downloading entrypoints-0.3-py2.py3-none-any.whl (11 kB)
Collecting pyinotify; sys_platform == "linux"
  Downloading pyinotify-0.9.6.tar.gz (60 kB)
     |████████████████████████████████| 60 kB 7.1 MB/s
Collecting cloudpickle
  Downloading cloudpickle-1.6.0-py3-none-any.whl (23 kB)
Collecting traitlets
  Downloading traitlets-5.0.5-py3-none-any.whl (100 kB)
     |████████████████████████████████| 100 kB 11.1 MB/s
Collecting ipython-genutils
  Downloading ipython_genutils-0.2.0-py2.py3-none-any.whl (26 kB)
Using legacy 'setup.py install' for pyinotify, since package 'wheel' is not installed.
Installing collected packages: pyinotify, cloudpickle, doit, ipython-genutils, traitlets, jupyter-core, entrypoints, jupyterlite
    Running setup.py install for pyinotify ... done
Successfully installed cloudpickle-1.6.0 doit-0.33.1 entrypoints-0.3 ipython-genutils-0.2.0 jupyter-core-4.7.1 jupyterlite-0.1.0a5 pyinotify-0.9.6 traitlets-5.0.5

Tento nástroj dokáže na základě specifikované konfigurace sestavit obsah statického webu, který zajistí možnost spuštění JupyterLite uživateli. Pokud ovšem mají být k dispozici i předpřipravené diáře, je nutné mít při sestavování statického webu nainstalován ještě jeden balíček:

$ pip3 install --user jupyter_server
 
Collecting jupyter_server
  Downloading jupyter_server-1.9.0-py3-none-any.whl (389 kB)
     |████████████████████████████████| 389 kB 2.8 MB/s
Collecting nbformat
  Downloading nbformat-5.1.3-py3-none-any.whl (178 kB)
     |████████████████████████████████| 178 kB 3.8 MB/s
Requirement already satisfied: ipython-genutils in /home/tester/.local/lib/python3.9/site-packages (from jupyter_server) (0.2.0)
Collecting Send2Trash
  Downloading Send2Trash-1.7.1-py3-none-any.whl (17 kB)
  ...
  ...
  ...
Running setup.py install for pandocfilters ... done
Successfully installed MarkupSafe-2.0.1 Send2Trash-1.7.1 anyio-3.2.1 argon2-cffi-20.1.0 async-generator-1.10 attrs-21.2.0 bleach-3.3.1 certifi-2021.5.30 cffi-1.14.6 charset-normalizer-2.0.3 defusedxml-0.7.1 idna-3.2 jinja2-3.0.1 jsonschema-3.2.0 jupyter-client-6.1.12 jupyter-server-1.9.0 jupyterlab-pygments-0.1.2 mistune-0.8.4 nbclient-0.5.3 nbconvert-6.1.0 nbformat-5.1.3 nest-asyncio-1.5.1 packaging-21.0 pandocfilters-1.4.3 prometheus-client-0.11.0 ptyprocess-0.7.0 pycparser-2.20 pygments-2.9.0 pyparsing-2.4.7 pyrsistent-0.18.0 pyzmq-22.1.0 requests-2.26.0 requests-unixsocket-0.2.0 sniffio-1.2.0 terminado-0.10.1 testpath-0.5.0 tornado-6.1 urllib3-1.26.6 webencodings-0.5.1 websocket-client-1.1.0
Poznámka: v případě, že tento balíček nebude nainstalován, nebudou diáře korektně zařazeny do statického webu – tato důležitá informace prozatím v oficiální dokumentaci chybí.

8. Sestavení statického webu s JupyterLite

V této chvíli by měly být k dispozici všechny potřebné nástroje nutné pro sestavení statického webu, který sám o sobě zajistí uživatelům přístup k JupyterLite, a to s využitím prakticky jakéhokoli webového serveru – ten pouze musí umět poskytovat statické soubory; nemusí již umět spouštět skripty ani žádný middleware.

Takový statický web připravíme příkazem:

$ jupyter lite init
 
static:jupyter-lite.json
.  pre_status:static:jupyter-lite.json
    tarball:  jupyterlite-app-0.1.0-alpha.5.tgz 19MB
    output:   /home/tester/_output
    lite dir: /home/tester
    apps:     ('lab', 'retro')
archive:archive
contents:contents
lite:jupyter-lite.json
serve:contents
settings:overrides
.  status:archive:archive
[LiteInitApp] No archive (yet): tester-jupyterlite.tgz
.  status:contents:contents
    contents: 0 files
.  status:lite:jupyter-lite.json
[LiteInitApp]     jupyter-lite.(json|ipynb): 0 files
.  status:serve:contents
    will serve 8000 with: stdlib
.  status:settings:overrides
    overrides.json: 0
static:output_dir
.  pre_init:static:output_dir
static:unpack
.  init:static:unpack

Po dokončení tohoto příkazu by měl být vytvořen podadresář _output obsahující kýžený obsah statického webu. Můžeme se tedy pokusit spustit webový server (ten nejjednodušší, který navíc již v systému je nainstalován) a posléze na server přistoupit z jiného počítače. Přepneme se do vytvořeného podadresáře:

$ cd _output

A spustíme webový server:

$ python -m http.server
 
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
Poznámka: v případě, že přístup na web server skončí s chybou (a současně server nevypisuje žádné zprávy), pravděpodobně to znamená, že byl přístup zakázán pravidly firewallu.

9. Zobrazení uživatelského rozhraní JupyterLite v prohlížeči

Ve chvíli, kdy webový server dodávající statický obsah běží, se můžeme ve webovém prohlížeči (ten může být provozován na jiném počítači) připojit na port :8000. Měla by se zobrazit stránka se standardním uživatelským rozhraním nástroje JupyterLite, která vypadá následovně:

Obrázek 8: Úvodní stránka se standardním uživatelským rozhraním JupyterLite.

V případě, že na konec adresy doplníme ještě část „/retro“ (bez uvozovek), zobrazí se poněkud odlišná stránka, která odpovídá původnímu designu JupyterNotebooku popř. IPython Notebooku:

Obrázek 9: Úvodní stránka s původním uživatelským rozhraním Jupyter Notebooku či IPython Notebooku.

Po funkční stránce jsou obě stránky prakticky rovnocenné. Můžeme z nich otevřít existujující diáře (popíšeme si v dalším textu) nebo vytvořit diář nový výběrem příslušného kernelu (Pyolite):

Obrázek 10: Nový diář otevřený v rámci projektu JupyterLite.

10. Sledování interní činnosti projektu JupyterLite

Při otevírání prvního diáře je vhodné si nechat zobrazit vývojovou konzoli, konkrétně list Network. V něm se zobrazí všechny soubory stahované jak z našeho serveru se statickým obsahem, tak i z dalších serverů. Mj. se stahuje i celý přeložený Pyodide:

Obrázek 11: Při prvním otevírání diáře se stahuje přibližně stovka souborů.

Poznámka: podívat se můžete i na přímo na konzoli se zprávami, do které Pyodide vypisuje informace o jednotlivých komponentách, které načítá a inicializuje.

Po otevření diáře (či více diářů) se tyto uloží do lokální paměti webového prohlížeče. Velikost uložených dat je pochopitelně možné taktéž zobrazit:

Obrázek 12: Dva diáře společně s dalšími kontextovými daty zabraly přibližně 450 kB.

A konečně je možné na speciální stránce s adresou about:performance sledovat objem alokované paměti a (přibližné) vytížení procesoru:

Obrázek 13: Sledování alokovaného objemu paměti a taktéž vytížení procesoru jednotlivými stránkami otevřenými ve webovém prohlížeči.

11. Server s vlastními diáři

Dalším krokem při nasazování nástroje JupyterLite na server je přidání vlastních diářů (notebooků), které si budou moci uživatelé otevřít, prohlížet, spouštět jednotlivé příkazy a popř. je i upravovat. Veškeré úpravy ovšem budou pouze lokální a platné v rámci prohlížeče uživatelů, protože zpětný zápis diáře na server není (takto jednoduše) možný – což ostatně přesně odpovídá tomu, proč se vlastně JupyterLite používá, tedy pro přenesení všech výpočtů na stranu klienta.

Příprava diářů je jednoduchá, protože je postačuje umístit do nějakého adresáře a následně spustit nám již známý příkaz jupyter lite build, ovšem navíc se specifikací adresáře či adresářů s diáři.

Nejprve naklonujeme repositář s množstvím připravených diářů:

$ git clone http://github.com/tisnik/jupyter-notebook-examples.git
 
Cloning into 'jupyter-notebook-examples'...
warning: redirecting to https://github.com/tisnik/jupyter-notebook-examples.git/
remote: Enumerating objects: 643, done.
remote: Counting objects: 100% (643/643), done.
remote: Compressing objects: 100% (366/366), done.
remote: Total 643 (delta 301), reused 606 (delta 267), pack-reused 0
Receiving objects: 100% (643/643), 7.11 MiB | 9.93 MiB/s, done.
Resolving deltas: 100% (301/301), done.

V dalším kroku si necháme připravit statický web i s těmito diáři:

$ cd jupyter-notebook-examples/
 
$ jupyter lite build --files .
 
static:jupyter-lite.json
.  pre_status:static:jupyter-lite.json
    tarball:  jupyterlite-app-0.1.0-alpha.5.tgz 19MB
    output:   /home/tester/work2/jupyter-notebook-examples/_output
    lite dir: /home/tester/work2/jupyter-notebook-examples
    apps:     ('lab', 'retro')
archive:archive
contents:contents
lite:jupyter-lite.json
serve:contents
settings:overrides
.  status:archive:archive
[LiteBuildApp] No archive (yet): jupyter-notebook-examples-jupyterlite.tgz
.  status:contents:contents
    contents: 196 files
.  status:lite:jupyter-lite.json
[LiteBuildApp]     jupyter-lite.(json|ipynb): 0 files
.  status:serve:contents
    will serve 8000 with: tornado
.  status:settings:overrides
    overrides.json: 0
static:output_dir
.  pre_init:static:output_dir
static:unpack
.  init:static:unpack
contents:copy:/files/Clojupyter - BufferedBitmap.ipynb
contents:copy:/files/Clojupyter - Importing clojure.repl namespace.ipynb
   ...
   ...
   ...
contents:contents:clojupyter-project/test/xyz
contents:contents:.
federated_extensions:patch
.  post_build:contents:contents:R
.  post_build:contents:contents:calysto_hy
.  post_build:contents:contents:clojupyter
.  post_build:contents:contents:clojupyter-project
.  post_build:contents:contents:courses
.  post_build:contents:contents:docs
.  post_build:contents:contents:matplotlib
.  post_build:contents:contents:pandas
.  post_build:contents:contents:push-pull-model-benchmarks
.  post_build:contents:contents:raster_images
.  post_build:contents:contents:clojupyter-project/doc
.  post_build:contents:contents:clojupyter-project/src
.  post_build:contents:contents:clojupyter-project/test
.  post_build:contents:contents:clojupyter-project/src/xyz
.  post_build:contents:contents:clojupyter-project/test/xyz
.  post_build:contents:contents:.
.  post_build:federated_extensions:patch

Výsledkem činnosti tohoto příkazu bude nový podadresář, který je implicitně pojmenovaný _output. V něm je opět umístěna kostra celého JupyterLite, ovšem navíc jsou do něho umístěny i diáře.

Opět spustíme HTTP server nad daným podadresářem _output (původní HTTP server je nutné buď zastavit, nebo použít odlišný port):

$ cd _output
 
$ python -m http.server
 
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...

Po otevření webového prostředí by se měl adresář či adresáře s diáři zobrazit v nabídce:

Obrázek 14: Adresář s diáři zobrazený v novém webovém prostředí.

Obrázek 15: Seznam připravených diářů v novém webovém prostředí.

To samé ostatně platí i při použití původního uživatelského prostředí Jupyter Notebooku (povšimněte si odlišné adresy):

Obrázek 16: Adresář s diáři zobrazený v původním webovém prostředí.

Obrázek 17: Seznam připravených diářů v původním webovém prostředí.

12. Knihovny dostupné v základní instalaci projektu JupyterLite

Nyní, když máme k dispozici sadu diářů připravených pro různé účely, si můžeme vyzkoušet, které knihovny jsou v nástroji JupyterLite dostupné. Prozatím se stále budeme soustředit na využití programovacího jazyka Python – možnosti nabízené JavaScriptem alespoň v kontextu tohoto článku nebudeme zmiňovat, protože se JavaScriptem (a především jeho knihovnami) v prostředí Jupyteru budeme zabývat v samostatném článku.

Pochopitelně je k dispozici základní knihovna Pythonu, s výjimkou těch funkcí, které vyžadují specifické vlastnosti poskytované operačním systémem, jež nemají svoji variantu dostupnou v prostředí webového prohlížeče. Ovšem v rámci projektu Pyodide byly přidány i další knihovny, resp. přesněji řečeno jejich verze přeložené pro WebAssembly – a tato „maličkost“ je důležitá zejména v kontextu knihovny NumPy, jejíž webová varianta zdaleka nedosahuje výpočetní rychlosti varianty nativní.

Obrázek 18: Problémy podle očekávání nastávají při pokusu o práci s lokálními soubory.

Poznámka: v praxi (resp. přesněji řečeno v některých oblastech, v nichž je Jupyter Notebook používá) mohou chybět například knihovny urllib2 a request.

13. NumPy

K dispozici je ovšem knihovna NumPy, která je v komunitě Jupyter Notebooku velmi často používaná. Pochopitelně muselo dojít k překladu původně nativních částí této knihovny do WebAssembly, což mj. znamená zpomalení výpočtů. Nicméně tato knihovna je stále velmi dobře použitelná.

Obrázek 19: Společné použití knihoven NumPy a Matplotlib.

14. Matplotlib

Využít lze i knihovnu Matplotlib, ovšem za předpokladu, že jsou grafy přímo zobrazeny v ploše webového prohlížeče. Pokud se ovšem používá funkce plg.savefig() pro uložení obrázku s grafem na disk, nebudou tyto obrázky uloženy na souborový systém (což je vlastně dobře, protože prohlížeč zde nabízí sandboxing).

Obrázek 20: Společné použití knihoven NumPy a Matplotlib.

15. Rychlost výpočtů v porovnání s nativním Jupyter Notebookem

Při spouštění výpočtů v JupyterLite je nutné se připravit na to, že některé výpočty budou pomalejší, a to mnohdy značně. Následující příklad tento rozdíl ukazuje. Jedná se o relativně pomalý výpočet nad NumPy polem. JupyterLite tento výpočet dokončil za 2 minuty a 22 sekund, zatímco kernel založený na CPythonu ten stejný výpočet dokončil za 20 sekund:

Obrázek 21: Výpočet v JupyterLite trval 2 minuty 22 sekund.

Obrázek 22: Stejný výpočet, ovšem spuštěný z klasického Jupyter Notebooku, trval pouze 20 sekund.

Větší budou i paměťové nároky, což je (pro ty stejné výpočty) ukázáno na dvou výstupech utility top:

Obrázek 23: Paměťové nároky moderních webových prohlížečů jsou mnohdy obrovské; v tomto případě kvůli běhu JupyterLite.

Obrázek 24: Na druhou stranu jsou paměťové nároky CPython kernelu relativně malé.

16. Další možnosti projektu JupyterLite

Kromě diářů dokáže JupyterLite do statického webového obsahu přidat i obrázky, dokumenty apod. a (teoreticky) ho lze využít pro tvorbu ucelených webových stránek (diáře založené na Markdownu). Výstup z JupyterLite (tedy statický obsah) lze v plné funkcionalitě uložit na github.io, o čemž se ostatně můžete snadno přesvědčit na adrese https://jupyterlite.github­.io/demo/lab/. A konečně dokáže JupyterLite přidat do tvořeného statického webu i další aplikace, kernely, doplňky daného ekosystému atd. Tyto možnosti budou představeny v navazujícím článku.

Obrázek 25: Složitější výpočty a vizualizace podivných atraktorů v nástroji JupyterLite.

17. Technologie WebAssembly (WASM)

V předchozím textu jsme se již několikrát zmínili o technologii nazvané WebAssembly či zkráceně pouze WASM. V první řadě se jedná o specifikaci virtuálního stroje, především jeho struktury (pro zajímavost: je založen na zásobníku operandů, podobně jako například virtuální stroj Javy) a taktéž ze specifikace jeho instrukčního souboru. Důležité přitom je, že současně používaná varianta WebAssembly je skutečně dosti nízkoúrovňová, takže (alespoň prozatím) neobsahuje například ani podporu pro automatickou správu paměti a i specifikace samotného runtime je dosti minimalistická. To je ovšem v mnoha ohledech nutno chápat jako přednost, protože u programovacích jazyků typu C, C++ či Rust není automatická správa paměti relevantní a jejich runtime je malý a naopak u jazyků typu Go je správce paměti přímo součástí runtime (zjednodušeně řečeno knihoven, které jsou slinkovány a tvoří výsledný bajtkód předávaný WebAssembly). Správa paměti řízená přímo WebAssembly je prozatím ve fázi vývoje a dnes ji nebudeme potřebovat ani si ji popisovat.

Již v předchozím odstavci jsme se zmínili o problematice runtime. Virtuální stroj WebAssembly akceptuje soubory s MIME typem nastaveným na application/wasm, které by měly obsahovat jak vlastní kód aplikace přeložený do bajtkódu, tak i veškerý podpůrný kód. V případě (například) programovacího jazyka Go to konkrétně znamená, že soubory s přeloženou aplikací jsou poměrně velké. I ta nejjednodušší aplikace přeložená do WebAssembly má velikost cca 1300 kB, protože je ve výsledku obsažený celý potřebný runtime i automatický správce paměti. A v případě Pythonu – viz předchozí kapitoly – je velikost runtime ještě o mnoho větší, což znamená, že první načtení celého podpůrného prostředí pro Jupyter Notebooky bude v případě Jupyteru Lite trvat delší dobu. Další spuštění již budou příslušné WASM soubory načítat z lokální diskové cache, takže inicializace celého prostředí by měla být prakticky okamžitá – řádově v sekundách, i méně.

bitcoin_skoleni

Poznámka ke kombinaci WASM + Go: velikost výsledného souboru se zvětšujícím se zdrojovým kódem aplikace dále již roste jen pomalu, ovšem i přesto je nutné počítat s tím, že první načtení a inicializace bajtkódu může být pomalá (mobilní připojení atd.) a může se tedy jednat o jeden z důvodů, proč WebAssembly a Go v praxi spíše nepoužívat. Na druhou stranu si představme například aplikaci typu „webové IDE“ nebo Google Docs – zde se doba nutná pro přenos cca jednoho či dvou megabajtů runtime pravděpodobně ztratí mezi stovkami kilobajtů dalších souborů (navíc se vlastně mnohdy mohou odstranit všechny JavaScriptové knihovny); u podobných aplikací se navíc očekává, že budou spuštěny delší dobu, na rozdíl od běžných webových prezentací.

Předností WebAssembly v porovnání s dalšími webovými technologiemi (transpilery, asm.js) by měla být větší rychlost provádění přeloženého kódu, která by s kvalitním just-in-time překladačem mohla dosahovat podobného výkonu jako nativní kód. A nesmíme zapomenout ani na fakt, že do WebAssembly lze překládat z mnoha běžných mainstreamových jazyků, například z C, C++, Go, Rustu atd. Pro Go je k dispozici vlastní překladač, pro ostatní zmíněné jazyky lze použít Emscripten.

18. Odkazy na články o Jupyter Notebooku

Se samotným nástrojem Jupyter Notebook jsme se již na stránkách Rootu čtyřikrát setkali, a to konkrétně v následujících článcích:

  1. Jupyter Notebook – nástroj pro programátory, výzkumníky i lektory
    https://www.root.cz/clanky/jupyter-notebook-nastroj-pro-programatory-vyzkumniky-i-lektory/
  2. Tvorba grafů v Jupyter Notebooku s využitím knihovny Matplotlib
    https://www.root.cz/clanky/tvorba-grafu-v-jupyter-notebooku-s-vyuzitim-knihovny-matplotlib/
  3. Tvorba grafů v Jupyter Notebooku s využitím knihovny Matplotlib (dokončení)
    https://www.root.cz/clanky/tvorba-grafu-v-jupyter-notebooku-s-vyuzitim-knihovny-matplotlib-dokonceni/
  4. Jupyter Notebook – operace s rastrovými obrázky a UML diagramy, literate programming
    https://www.root.cz/clanky/jupyter-notebook-operace-s-rastrovymi-obrazky-a-uml-diagramy-literate-programming/
  5. Interpret programovacího jazyka Clojure integrovaný do Jupyter Notebooku
    https://www.root.cz/clanky/interpret-programovaciho-jazyka-clojure-integrovany-do-jupyter-notebooku/
  6. Calysto Hy: integrace programovacího jazyka Hy s Jupyter Notebookem
    https://www.root.cz/clanky/calysto-hy-integrace-programovaciho-jazyka-hy-s-jupyter-notebookem/

19. Odkazy na články a videa s tématem technologie WebAssembly

  1. Využití WebAssembly z programovacího jazyka Go
    https://www.root.cz/clanky/vyuziti-webassembly-z-programovaciho-jazyka-go/
  2. WebAssembly prošlo standardizací ve W3C, byla vydána verze 1.0
    https://www.root.cz/zpravic­ky/webassembly-proslo-standardizaci-ve-w3c-byla-vydana-verze-1–0/
  3. WebAssembly
    https://webassembly.org/
  4. WebAssembly na Wiki Golangu
    https://github.com/golang/go/wi­ki/WebAssembly
  5. The future of WebAssembly – A look at upcoming features and proposals
    https://blog.scottlogic.com/2018/07/20/wasm-future.html
  6. Writing WebAssembly By Hand
    https://blog.scottlogic.com/2018/04/26/we­bassembly-by-hand.html
  7. WebAssembly Specification
    https://webassembly.github­.io/spec/core/index.html
  8. Index of Instructions
    https://webassembly.github­.io/spec/core/appendix/in­dex-instructions.html
  9. The WebAssembly Binary Toolkit
    https://github.com/WebAssembly/wabt
  10. Will WebAssembly replace JavaScript? Or Will WASM Make JavaScript More Valuable in Future?
    https://dev.to/vaibhavshah/will-webassembly-replace-javascript-or-will-wasm-make-javascript-more-valuable-in-future-5c6e
  11. Roadmap (pro WebAssemly)
    https://webassembly.org/roadmap/
  12. S-expression
    https://en.wikipedia.org/wiki/S-expression
  13. Understanding WebAssembly text format
    https://developer.mozilla.org/en-US/docs/WebAssembly/Under­standing_the_text_format
  14. Learning Golang through WebAssembly – Part 1, Introduction and setup
    https://www.aaron-powell.com/posts/2019–02–04-golang-wasm-1-introduction/
  15. Learning Golang through WebAssembly – Part 2, Writing your first piece of Go
    https://www.aaron-powell.com/posts/2019–02–05-golang-wasm-2-writing-go/
  16. Learning Golang through WebAssembly – Part 3, Interacting with JavaScript from Go
    https://www.aaron-powell.com/posts/2019–02–06-golang-wasm-3-interacting-with-js-from-go/
  17. Golang webassembly (wasm) testing with examples
    https://jelinden.fi/blog/golang-webassembly-wasm-testing-with-examples/qB7Tb2KmR
  18. Use Cases (of WebAssembly)
    https://webassembly.org/docs/use-cases/
  19. Tabulka s podporou WebAssembly v různých prohlížečích
    https://caniuse.com/#feat=wasm
  20. An introduction to WebAssembly
    https://www.youtube.com/wat­ch?v=3sU557ZKjUs
  21. Web Assembly (WASM) in 100 Seconds
    https://www.youtube.com/wat­ch?v=cbB3QEwWMlA
  22. What is WebAssembly?
    https://www.youtube.com/wat­ch?v=kTZoZbxDudw

20. Další odkazy na Internetu

  1. JupyterLite na PyPi
    https://pypi.org/project/jupyterlite/
  2. JupyterLite na GitHubu
    https://github.com/jupyter­lite/jupyterlite
  3. Dokumentace k projektu JupyterLite
    https://github.com/jupyter­lite/jupyterlite
  4. Notebook interface
    https://en.wikipedia.org/wi­ki/Notebook_interface
  5. Jypyter: open source, interactive data science and scientific computing across over 40 programming languages
    https://jupyter.org/
  6. Matplotlib Home Page
    http://matplotlib.org/
  7. Matplotlib (Wikipedia)
    https://en.wikipedia.org/wi­ki/Matplotlib
  8. Popis barvových map modulu matplotlib.cm
    https://gist.github.com/en­dolith/2719900#id7
  9. Ukázky (palety) barvových map modulu matplotlib.cm
    http://matplotlib.org/exam­ples/color/colormaps_refe­rence.html
  10. Galerie grafů vytvořených v Matplotlibu
    https://matplotlib.org/3.2.1/gallery/
  11. showcase example code: xkcd.py
    https://matplotlib.org/xkcd/e­xamples/showcase/xkcd.html
  12. Customising contour plots in matplotlib
    https://philbull.wordpres­s.com/2012/12/27/customising-contour-plots-in-matplotlib/
  13. Graphics with Matplotlib
    http://kestrel.nmt.edu/~ra­ymond/software/python_notes/pa­per004.html
  14. The IPython Notebook
    http://ipython.org/notebook.html
  15. nbviewer: a simple way to share Jupyter Notebooks
    https://nbviewer.jupyter.org/
  16. Back to the Future: Lisp as a Base for a Statistical Computing System
    https://www.stat.auckland­.ac.nz/~ihaka/downloads/Com­pstat-2008.pdf
  17. gg4clj: a simple wrapper for using R's ggplot2 in Clojure and Gorilla REPL
    https://github.com/JonyEpsilon/gg4clj
  18. Analemma: a Clojure-based SVG DSL and charting library
    http://liebke.github.io/analemma/
  19. Clojupyter: a Jupyter kernel for Clojure
    https://github.com/roryk/clojupyter
  20. Incanter is a Clojure-based, R-like platform for statistical computing and graphics.
    http://incanter.org/
  21. Evolution of incanter (Gource Visualization)
    https://www.youtube.com/wat­ch?v=TVfL5nPELr4
  22. Questions tagged [incanter] (na Stack Overflow)
    https://stackoverflow.com/qu­estions/tagged/incanter?sor­t=active
  23. Data Sorcery with Clojure
    https://data-sorcery.org/contents/
  24. What is REPL?
    https://pythonprogramminglan­guage.com/repl/
  25. What is a REPL?
    https://codewith.mu/en/tu­torials/1.0/repl
  26. Programming at the REPL: Introduction
    https://clojure.org/guides/re­pl/introduction
  27. What is REPL? (Quora)
    https://www.quora.com/What-is-REPL
  28. Gorilla REPL: interaktivní prostředí pro programovací jazyk Clojure
    https://www.root.cz/clanky/gorilla-repl-interaktivni-prostredi-pro-programovaci-jazyk-clojure/
  29. R Markdown: The Definitive Guide
    https://bookdown.org/yihui/rmarkdown/
  30. Single-page application
    https://en.wikipedia.org/wiki/Single-page_application
  31. Video streaming in the Jupyter Notebook
    https://towardsdatascience.com/video-streaming-in-the-jupyter-notebook-635bc5809e85
  32. How IPython and Jupyter Notebook work
    https://jupyter.readthedoc­s.io/en/latest/architectu­re/how_jupyter_ipython_wor­k.html
  33. Jupyter kernels
    https://github.com/jupyter/ju­pyter/wiki/Jupyter-kernels
  34. Keras: The Python Deep Learning library
    https://keras.io/
  35. TensorFlow
    https://www.tensorflow.org/
  36. PyTorch
    https://pytorch.org/
  37. Seriál Torch: framework pro strojové učení
    https://www.root.cz/serialy/torch-framework-pro-strojove-uceni/
  38. Scikit-learn
    https://scikit-learn.org/stable/
  39. Java Interop (Clojure)
    https://clojure.org/referen­ce/java_interop
  40. Obrazy s balíčky Jupyter Notebooku pro Docker
    https://hub.docker.com/u/jupyter/#!
  41. Správce balíčků Conda (dokumentace)
    https://docs.conda.io/en/latest/
  42. Lorenzův atraktor
    https://www.root.cz/clanky/fraktaly-v-pocitacove-grafice-vi/#k02
  43. Lorenzův atraktor
    https://www.root.cz/clanky/fraktaly-v-pocitacove-grafice-iii/#k03
  44. Graphics with Matplotlib
    http://kestrel.nmt.edu/~ra­ymond/software/python_notes/pa­per004.html
  45. Embedding Matplotlib Animations in Jupyter Notebooks
    http://louistiao.me/posts/no­tebooks/embedding-matplotlib-animations-in-jupyter-notebooks/
  46. Literate programing, Kolokviální práce Pavla Starého
    https://www.fi.muni.cz/us­r/jkucera/pv109/starylp.htm
  47. PlantUML (home page)
    http://plantuml.sourceforge.net/
  48. PlantUML (download page)
    http://sourceforge.net/pro­jects/plantuml/files/plan­tuml.jar/download
  49. PlantUML (Language Reference Guide)
    http://plantuml.sourcefor­ge.net/PlantUML_Language_Re­ference_Guide.pdf
  50. Plain-text diagrams take shape in Asciidoctor!
    http://asciidoctor.org/new­s/2014/02/18/plain-text-diagrams-in-asciidoctor/
  51. Graphviz – Graph Visualization Software
    http://www.graphviz.org/
  52. graphviz (Manual Page)
    http://www.root.cz/man/7/graphviz/
  53. PIL: The friendly PIL fork (home page)
    https://python-pillow.org/
  54. Python Imaging Library (PIL), (home page)
    http://www.pythonware.com/pro­ducts/pil/
  55. PIL 1.1.6 na PyPi
    https://pypi.org/project/PIL/
  56. Pillow 5.2.0 na PyPi
    https://pypi.org/project/Pillow/
  57. Python Imaging Library na Wikipedii
    https://en.wikipedia.org/wi­ki/Python_Imaging_Library
  58. Pillow na GitHubu
    https://github.com/python-pillow/Pillow
  59. Pillow – dokumentace na readthedocs.io
    http://pillow.readthedocs­.io/en/5.2.x/
  60. How to use Pillow, a fork of PIL
    https://www.pythonforbegin­ners.com/gui/how-to-use-pillow
  61. Pyodide
    https://github.com/pyodide/pyodide
  62. Deploying
    https://jupyterlite.readthe­docs.io/en/latest/deployin­g.html
  63. Pyodide: Bringing the scientific Python stack to the browser
    https://hacks.mozilla.org/2019/04/py­odide-bringing-the-scientific-python-stack-to-the-browser/
  64. Dan Callahan – Keynote – PyCon 2018
    https://www.youtube.com/wat­ch?v=ITksU31c1WY
  65. Web Storage API
    https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API

Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.