現(xiàn)在越來(lái)越多的軟件都Web化,瀏覽器化。雖然科學(xué)計(jì)算是一計(jì)算密集型的方向,對(duì)性能要求和實(shí)時(shí)性較高。但是數(shù)據(jù)計(jì)算方面也一直在做著這樣的探索和發(fā)展。 Jypyer notbook項(xiàng)目讓科學(xué)計(jì)算真正實(shí)現(xiàn)了Web化,而JS語(yǔ)言的發(fā)展和WebAssembly技術(shù)的興起,讓科學(xué)計(jì)算的瀏覽器化,在客戶端實(shí)現(xiàn)數(shù)據(jù)計(jì)算處理和可視化變成了可能。今天蟲蟲要給大家介紹就是一款來(lái)自Mozilla的實(shí)驗(yàn)項(xiàng)目Pyodide,一款用于在瀏覽器中運(yùn)行完整Python科學(xué)計(jì)算處理工具棧環(huán)境的軟件。 ![]() 概述 Pyodide項(xiàng)目源于Mozilla的項(xiàng)目Iodide。 Iodide是基于Web技術(shù)的數(shù)據(jù)科學(xué)實(shí)驗(yàn)和通信工具。它旨在在瀏覽器中進(jìn)行數(shù)據(jù)計(jì)算。問題是通用的瀏覽器語(yǔ)言JS,沒有成熟的數(shù)據(jù)科學(xué)處理庫(kù),也缺乏一些數(shù)值計(jì)算很有用功能和數(shù)據(jù)結(jié)構(gòu),比如運(yùn)算符重載等。雖然完善JS語(yǔ)言本身是一條路,但是這條路太慢,所以有必要投機(jī)取巧的走一條捷徑出來(lái)。這就是Pyodide項(xiàng)目的所做的事情:通過將成熟活躍的Python科學(xué)計(jì)算工具棧引入瀏覽器來(lái)滿足數(shù)據(jù)科學(xué)計(jì)算的需要。Pyodide提供了一個(gè)完整的標(biāo)準(zhǔn)Python解釋器,它完全在瀏覽器中運(yùn)行,可以完全訪問瀏覽器的Web API。下面以一個(gè)快速實(shí)例開始: ![]() 代碼顯示效果如下: 了解更多關(guān)于Pyodide可以做的事情的最好方法就是去嘗試吧!有一個(gè)演示筆記本(50MB下載),介紹了高級(jí)功能。本文的其余部分將更深入地探討其工作原理。 技術(shù)架構(gòu) 類似項(xiàng)目分析 Pydodie設(shè)計(jì)時(shí)候參考了很多現(xiàn)有項(xiàng)目,在實(shí)現(xiàn)Python到瀏覽器這'最后一公里'問題上,市面上已經(jīng)有很多的項(xiàng)目,但是目前還沒有一個(gè)項(xiàng)目可以做到Python科學(xué)計(jì)算棧的轉(zhuǎn)化,該棧包括不限于Python類庫(kù):NumPy,Pandas,Scipy以及Matplotlib。 Transcrypt項(xiàng)目可以實(shí)現(xiàn)Python到JS的轉(zhuǎn)換。由于轉(zhuǎn)換步驟本身發(fā)生在Python中,所以你需要提前完成所有的轉(zhuǎn)換,或通過與服務(wù)器通信來(lái)完成這項(xiàng)工作。這并不能實(shí)現(xiàn)用戶在瀏覽器中編寫Python并實(shí)現(xiàn)即寫急用的目標(biāo)。 Brython和Skulpt項(xiàng)目實(shí)現(xiàn)了將標(biāo)準(zhǔn)Python解釋器重寫為JS,可以直接在瀏覽器中運(yùn)行Python代碼。但是它們都是對(duì)Python的全新實(shí)現(xiàn),并且通過JS中引導(dǎo),所以他們無(wú)法兼容C編寫的Python擴(kuò)展,比如NumPy和Pandas。因此,無(wú)法引入數(shù)據(jù)科學(xué)工具。 PyPyJs項(xiàng)目是使用emscripten和JS對(duì)PyPy的瀏覽器實(shí)現(xiàn)。就像PyPy一樣它可以快速地運(yùn)行Python代碼。同樣它也有于PyPy同樣的C擴(kuò)展性能問題。 上面這很多項(xiàng)目都無(wú)法解決Python科學(xué)計(jì)算的問題,這促成了Pydodie的出現(xiàn):構(gòu)建一個(gè)盡可能基于Python的標(biāo)準(zhǔn)并能兼容實(shí)現(xiàn)大多數(shù)數(shù)據(jù)科學(xué)家已經(jīng)使用的Python科學(xué)堆棧的工具庫(kù)的軟件。 Pydodie項(xiàng)目技術(shù)架構(gòu)的關(guān)鍵技術(shù)就是新興的emscripten和WebAssembly。使用他們實(shí)現(xiàn)將C語(yǔ)言編寫的現(xiàn)有代碼庫(kù)移植到瀏覽器運(yùn)行。Pyodide使用Python化的emscripten類庫(kù)cpython-emscripten為基礎(chǔ)。 Emscripten和WebAssembly 關(guān)于emscripten互聯(lián)網(wǎng)上有大量的介紹,在此不在贅述,在Pyodide項(xiàng)目中它的作用是: 實(shí)現(xiàn)從C/C++到WebAssembly的編譯器。 實(shí)現(xiàn)兼容性層,使瀏覽器變?yōu)橐粋€(gè)本機(jī)計(jì)算環(huán)境。 WebAssembly是一種在現(xiàn)代Web瀏覽器中運(yùn)行的新語(yǔ)言,是對(duì)JS腳本的補(bǔ)充。它以接近本機(jī)的性能運(yùn)行在瀏覽器上,旨在作為C和C++等低級(jí)語(yǔ)言的編譯目標(biāo)。 關(guān)于WebAssembly蟲蟲之前的文章中有介紹過,關(guān)注過蟲蟲的朋友可以在歷史文章中瀏覽學(xué)習(xí)。 我們知道,實(shí)現(xiàn)主流的Python解釋器是CPython是用C語(yǔ)言實(shí)現(xiàn)的,所以使用emscripten可以將其編譯為WebAssembly。 Pyodide組成和實(shí)現(xiàn)步驟 Pyodide主要架構(gòu)組成如下: 將主流Python解釋器(CPython)的源代碼和科學(xué)計(jì)算包(NumPy等)將其打包在一起,使用emscripten的編譯器將它們編譯為WebAssembly。 但是如果只是在瀏覽器總執(zhí)行這個(gè)WebAssembly還不夠,比如,無(wú)法在Web瀏覽器中執(zhí)行文件操作(加載和保存文件)。為此Pyodide還引入了用JavaScript編寫的虛擬文件系統(tǒng)。這些虛擬的文件駐留在瀏覽器選項(xiàng)卡性內(nèi)存中。 通過模擬文件系統(tǒng)和標(biāo)準(zhǔn)科學(xué)計(jì)算環(huán)境的其他功能,將實(shí)現(xiàn)通過極少的改動(dòng)將整個(gè)Python科學(xué)計(jì)算環(huán)境挪到Web瀏覽器。整個(gè)實(shí)現(xiàn)步驟如下: 1、已編譯的Python解釋器為WebAssembly。 2、通過emscripten提供的一系列的JS,用來(lái)提供系統(tǒng)仿真。 3、打包文件系統(tǒng),包含Python解釋器所需的所有文件,包括Python標(biāo)準(zhǔn)庫(kù)。 這些文件可能非常大,比如Python本身為21MB,NumPy為7MB,等等依。好在這些軟件包只需要下載一次,然后將它們存儲(chǔ)在瀏覽器的緩存中。 局限性 通過運(yùn)行CPython的單元測(cè)試對(duì)Pyodide做持續(xù)測(cè)試的,以便了解其通用性。目前還有功能是無(wú)法用的,比如Python線程。 由于瀏覽器的安全沙箱限制,一些他功能(比如如低級(jí)網(wǎng)絡(luò)Socket)也不能正正常工作。 性能問題 在JS虛擬機(jī)中運(yùn)行Python解釋器會(huì)有性能損失,但是影響非常小,通過官方基準(zhǔn)測(cè)試中表明:在Firefox上的比本機(jī)慢1x-12x,Chrome上慢1x-16x。還有就是,在Python中運(yùn)行大量?jī)?nèi)部循環(huán)的代碼往往比依賴于NumPy執(zhí)行其內(nèi)部循環(huán)的代碼更慢。下面是在Firefox和Chrome對(duì)比同硬件本機(jī)中運(yùn)行各種純Python和Numpy基準(zhǔn)測(cè)試的結(jié)果。 ![]() 測(cè)試數(shù)據(jù)和方法鍵github倉(cāng)庫(kù)(iodide-project/) Python和JS的交互 如果Pyodide只能做到運(yùn)行Python代碼并寫入標(biāo)準(zhǔn)輸出,雖然不錯(cuò),但是沒有實(shí)用價(jià)值。最重要是實(shí)現(xiàn)與瀏覽器API以及其他JS庫(kù)的交互。 類型轉(zhuǎn)換 Pyodide隱式地對(duì)Python和JS類型的轉(zhuǎn)換,下圖展示了兩種語(yǔ)言類型轉(zhuǎn)換的細(xì)節(jié): ![]() Python中dicts和對(duì)象實(shí)例是兩種不同的類型。 dicts只是健值的映射。而對(duì)象通常具對(duì)象屬性和方法(methond)。在JS中沒有dicts對(duì)應(yīng)的數(shù)據(jù)結(jié)果,通用Object的類型來(lái)表示。 Ptdodide在兩者轉(zhuǎn)化的時(shí)候需要用到代理和鴨子類型 代理 代理是另一種語(yǔ)言中變量的包裝器。代理不是簡(jiǎn)單地在JS中讀取變量并根據(jù)Python結(jié)構(gòu)重寫它,代理保持原始JS變量并'按需'調(diào)用其方法。所以任何JS變量,都可以從Python完全訪問。 鴨子類型 鴨子類型是一個(gè)原則,而不是實(shí)際去問變量'你是鴨子嗎?', '你像鴨子一樣走路嗎?'和'你像鴨子一樣嘎嘎叫嗎?',然后推斷它是否是一只鴨子。通過鴨子類型Pyodide可以不用馬上考慮推如何轉(zhuǎn)換JS對(duì)象,而將其打包到代理中,讓使用它的代碼決定如何處理它。 當(dāng)然,這種方法并能一直有效這,鴨子實(shí)際上有可能是一只兔子。Pyodide也提供了明確轉(zhuǎn)換處理方法。 ![]() Pyodide使用這種高度交互,深度集成,潛在轉(zhuǎn)換的方法把Python和JS融為一體。用戶通過Python進(jìn)行數(shù)據(jù)處理,然后用JS實(shí)現(xiàn)其可視化。 訪問Web API和DOM 代理也是訪問Web API的關(guān)鍵。例如,Web API的很大部分位于文檔對(duì)象上。你可以通過以下方式從Python中獲得: from js import document 這會(huì)將 JS中的document對(duì)象作為代理引入到Python。然后在Python中調(diào)用它的方法: document.getElementById('myElement') 這些都通過代理來(lái)查找document對(duì)象可以即時(shí)執(zhí)行的操作。 Pyodide不需要包include所有的Web API的完整列表。 多維數(shù)組 有一些類型是數(shù)據(jù)計(jì)算必須要的數(shù)據(jù)類型,比如矩陣計(jì)算中用到的多維數(shù)組,Pyodide也特別支持這些數(shù)據(jù)。多維數(shù)組是值的集合,這些值都是同一類型,但是數(shù)量巨大。Pyodide的多維數(shù)組對(duì)比Python的列表或JS數(shù)組在性能上具有很大優(yōu)勢(shì)。 Python中,NumPy數(shù)組是多維數(shù)組的最常用的實(shí)現(xiàn)。JS中是TypedArrays,它只包含一個(gè)數(shù)字類型。但是這兩種類型都是一維的,多維數(shù)組需要在頂層來(lái)構(gòu)建。 由于現(xiàn)實(shí)中這些數(shù)組可能會(huì)變得非常大,在語(yǔ)言運(yùn)行時(shí)之間復(fù)制會(huì)非常消耗資源,而且是個(gè)非常耗時(shí)的操作。 Pyodide中利用多維數(shù)組可以無(wú)需復(fù)制就能在Python和JS之間共享數(shù)據(jù)。多維數(shù)組通常使用少量元數(shù)據(jù)來(lái)實(shí)現(xiàn),這些元數(shù)據(jù)描述了值的類型,數(shù)組的形狀和內(nèi)存布局。數(shù)據(jù)本身通過指向內(nèi)存中另一個(gè)位置的指針在元數(shù)據(jù)中索引。這個(gè)內(nèi)存地址位于WebAssembly堆區(qū)的,可以在JS和Python中訪問。通過在兩種語(yǔ)言中復(fù)制元數(shù)據(jù),來(lái)達(dá)到共享其指針指向的WebAssembly堆數(shù)據(jù)。 ![]() 實(shí)時(shí)交互式可視化 在客戶端瀏覽器中進(jìn)行科學(xué)數(shù)據(jù)計(jì)算的優(yōu)點(diǎn)之一是,交互式可視化不必通過網(wǎng)絡(luò)進(jìn)行通信以重新處理和重新顯示其數(shù)據(jù)。這大大減少了交互的延遲。 完成實(shí)時(shí)交互可視的工作需要各部分的組件協(xié)同工作。下面是一個(gè)官方交互式示例動(dòng)態(tài)圖,它展示了使用matplotlib進(jìn)行對(duì)數(shù)正態(tài)分布。 首先,使用Numpy在Python中生成隨機(jī)數(shù)據(jù)。 其次,在Matplotlib獲取該數(shù)據(jù),并使用其內(nèi)置的軟件渲染器繪制它。 最后通過Pyodide零拷貝數(shù)組共享將像素發(fā)送回JS端,在HTML畫布中呈現(xiàn)出來(lái)在瀏覽器中將這些像素顯示出來(lái)。 用于支持交互性的鼠標(biāo)和鍵盤事件由從Web瀏覽器調(diào)用Python的回調(diào)函數(shù)處理。 打包 Python科學(xué)計(jì)算工具棧由很多分散的軟件包構(gòu)成,這些包協(xié)同工作創(chuàng)建一個(gè)高效的計(jì)算環(huán)境。工具棧中最受歡迎的是NumPy(數(shù)值數(shù)組和基本計(jì)算),Scipy(更復(fù)雜的通用計(jì)算,如線性代數(shù)),Matplotlib(可視化)和Pandas(用于表格數(shù)據(jù)或數(shù)據(jù)幀處理)。目前Pyodide官方倉(cāng)庫(kù)中包含的包見下圖,更多的包還在不斷完善和添加中: ![]() 有些包很容易引入進(jìn)來(lái)。通常,使用純Python編寫而沒有其它編譯語(yǔ)言擴(kuò)展的包都非常容易。像Matplotlib這樣的項(xiàng)目需要使用特殊代碼在HTML畫布中顯示繪圖包為中等難度。而諸如Scipy這樣的包的引入則比較困難。 官方內(nèi)置的包有限,用戶可以根據(jù)需要自引入所需的個(gè)性化包,比如: import numpy as np 上面語(yǔ)法中,Pyodide會(huì)引入NumPy庫(kù)及其所有依賴項(xiàng),并將其加載到瀏覽器中。而且包引入瀏覽器后會(huì)被緩存起來(lái),下次加載時(shí)不需要重復(fù)下載。 給Pyodide打包添加新軟件包,目前還不支持動(dòng)態(tài)引入。需要手動(dòng)添加。據(jù)悉未來(lái)版本Pyodide將會(huì)增加對(duì)PyPI的支持。 多語(yǔ)言支持 Pyodide目前已經(jīng)得到很多語(yǔ)言社區(qū)的的關(guān)注,目前已經(jīng)有Julia,R,OCaml,Lua等語(yǔ)言實(shí)現(xiàn)良好的瀏覽器運(yùn)行時(shí)。Pyodide還與Iodide等網(wǎng)絡(luò)優(yōu)先工具實(shí)現(xiàn)了集成。 Pyodide定義了一個(gè)集成級(jí)別,用來(lái)實(shí)現(xiàn)與其他語(yǔ)言及工具的集成: 第一級(jí)別:字符串輸出,可以作為基本控制臺(tái)REPL(read-eval-print-loop)。 第二級(jí)別:支持將基本數(shù)據(jù)類型(數(shù)字,字符串,數(shù)組和對(duì)象)轉(zhuǎn)換為JS或從JS轉(zhuǎn)換。 第三級(jí)別:在客戶語(yǔ)言和JS之間共享類實(shí)例(帶方法的對(duì)象)。這允許Web API訪問。 第四級(jí)別:在客戶語(yǔ)言和JS之間共享科學(xué)計(jì)算相關(guān)類型(n維數(shù)組和數(shù)據(jù)框)。 結(jié)論 Pydodide提供了我們一種很酷的科學(xué)數(shù)據(jù)編程和用戶體驗(yàn)。雖然目前還處于實(shí)驗(yàn)性概念驗(yàn)階段,但是我們已經(jīng)可以考慮將其做為日常數(shù)據(jù)科學(xué)工作的選擇,并嘗試給它的完善壯大添磚加瓦。 |
|
來(lái)自: flyk0tcfb46p9f > 《AI》