Kompilowanie Pythona do WebAssembly

90

Czytałem, że można przekonwertować kod Pythona 2.7 na Web Assembly, ale nie mogę znaleźć ostatecznego przewodnika, jak to zrobić.

Do tej pory skompilowałem program C do Web Assembly przy użyciu Emscripten i wszystkich jego niezbędnych komponentów, więc wiem, że działa (przewodnik: http://webassembly.org/getting-started/developers-guide/ )

Jakie kroki muszę wykonać, aby to zrobić na komputerze z systemem Ubuntu? Czy muszę przekonwertować kod Pythona na kod bitowy LLVM, a następnie skompilować go za pomocą Emscripten? Jeśli tak, jak mógłbym to osiągnąć?

Robbie
źródło
1
@guettli github.com/pypyjs/pypyjs/issues/145
denfromufa
1
Sprawdź pyodide: hacks.mozilla.org/2019/04/…
Alex
1
Pyodide przenosi środowisko wykonawcze Pythona do przeglądarki przez WebAssembly: github.com/iodide-project/pyodide
guettli

Odpowiedzi:

146

WebAssembly vs asm.js

Najpierw rzućmy okiem jak w zasadzie WebAssembly różni się od asm.js i czy istnieje potencjał do ponownego wykorzystania istniejącej wiedzy i oprzyrządowania. Poniższe daje całkiem dobry przegląd:

Podsumujmy, WebAssembly (MVP, ponieważ w przybliżeniu jest więcej na jego mapie drogowej ):

  • jest binarnym formatem AST z typowaniem statycznym, który może być wykonywany przez istniejące silniki JavaScript (a tym samym AOT zdolny do JIT lub skompilowany),
  • jest o 10-20% bardziej zwarty (porównanie gzipem) i o rząd wielkości szybszy do przeanalizowania niż JavaScript,
  • może wyrazić więcej operacji niskopoziomowych, które nie pasują do składni JavaScript, przeczytaj asm.js (np. 64-bitowe liczby całkowite, specjalne instrukcje procesora, SIMD itp.)
  • można zamienić (do pewnego stopnia) na asm.js.

Dlatego obecnie WebAssembly jest iteracją w asm.js i jest przeznaczona tylko dla C / C ++ (i podobnych języków).

Python w sieci

Nie wygląda na to, że GC jest jedyną rzeczą, która powstrzymuje kod Pythona przed celowaniem w WebAssembly / asm.js. Oba reprezentują statycznie typowany kod niskiego poziomu, w którym kod Pythona nie może być (realistycznie) reprezentowany. Ponieważ obecny łańcuch narzędzi WebAssembly / asm.js jest oparty na LLVM, języku, który można łatwo skompilować do LLVM IR, można przekonwertować na WebAssembly / asm.js. Niestety, Python jest zbyt dynamiczny, aby również do niego pasować, o czym świadczy Unladen Swallow i kilka prób PyPy.

Ta prezentacja asm.js zawiera slajdy dotyczące stanu języków dynamicznych . Oznacza to, że obecnie możliwe jest tylko skompilowanie całej maszyny wirtualnej (implementacja języka w C / C ++) do WebAssembly / asm.js i zinterpretowanie (z JIT, jeśli to możliwe) oryginalnych źródeł. W przypadku Pythona istnieje kilka istniejących projektów:

  1. PyPy: PyPy.js ( wykład autora na PyCon ). Oto repozytorium wersji . Główny plik JS pypyjs.vm.jsma 13 MB (po 2 MB gzip -6) + stdlib w Pythonie + inne rzeczy.

  2. CPython: pyodide , EmPython , CPython-Emscripten , EmCPython itp. empython.jsTo 5,8 MB (po 2,1 MB gzip -6), brak standardowego biblioteki.

  3. Micropython: ten widelec .

    Nie było tam zbudowanego pliku JS, więc mogłem go zbudować za trzeci/emscripten/pomocą gotowego łańcucha narzędzi Emscripten. Coś jak:

     git clone https://github.com/matthewelse/micropython.git
     cd micropython
     docker run --rm -it -v $(pwd):/src trzeci/emscripten bash
     apt-get update && apt-get install -y python3
     cd emscripten
     make -j
     # to run REPL: npm install && nodejs server.js 
    

    Daje micropython.js1,1 MB (po 225 KB gzip -d). To ostatnie jest już czymś do rozważenia, jeśli potrzebujesz tylko bardzo zgodnej implementacji bez stdlib.

    Aby utworzyć kompilację WebAssembly, możesz zmienić wiersz 13 Makefilena

     CC = emcc -s RESERVED_FUNCTION_POINTERS=20 -s WASM=1
    

    Następnie make -jprodukuje:

     113 KB micropython.js
     240 KB micropython.wasm
    

    Możesz spojrzeć na wynik HTML programu emcc hello.c -s WASM=1 -o hello.html, aby zobaczyć, jak używać tych plików.

    W ten sposób możesz również potencjalnie zbudować PyPy i CPython w WebAssembly, aby zinterpretować aplikację Python w zgodnej przeglądarce.

Inną potencjalnie interesującą rzeczą jest Nuitka , kompilator Pythona do C ++. Potencjalnie możliwe jest zbudowanie aplikacji w języku Python w języku C ++, a następnie skompilowanie jej wraz z CPythonem za pomocą Emscripten. Ale praktycznie nie mam pojęcia, jak to zrobić.

Rozwiązania

Na razie, jeśli tworzysz konwencjonalną witrynę internetową lub aplikację internetową, w której pobranie kilku-megabajtowego pliku JS jest ledwie opcją, spójrz na transpilery Python-to-JavaScript (np. Transcrypt ) lub implementacje JavaScript Python (np. Brython ). Lub spróbuj szczęścia z innymi z listy języków, które kompilują się do JavaScript .

W przeciwnym razie, jeśli rozmiar pobierania nie stanowi problemu i jesteś gotowy, aby poradzić sobie z wieloma nierównymi krawędziami, wybierz jedną z trzech powyższych.

Aktualizacja Q3 2020

  1. Port JavaScript został zintegrowany z MicroPythonem. Żyje w portach / javascript .

  2. Port jest dostępny jako pakiet npm o nazwie MicroPython.js . Możesz to wypróbować w RunKit .

  3. W Rust istnieje aktywnie rozwijana implementacja języka Python o nazwie RustPython . Ponieważ Rust oficjalnie obsługuje WebAssembly jako cel kompilacji , nic dziwnego, że na początku pliku readme znajduje się link do wersji demonstracyjnej . Chociaż jest wcześnie. Ich zrzeczenie się następuje.

    RustPython jest w fazie rozwoju i nie powinien być używany w środowisku produkcyjnym lub w ustawieniach nietolerujących błędów.

    Nasza obecna kompilacja obsługuje tylko podzbiór składni Pythona.

saaj
źródło
1
Te rozmiary .js i .wasm nie są naprawdę sprawiedliwe. Kompresja strumienia jest dobrze obsługiwana i można jej użyć do zmniejszenia rozmiaru obu. Jak duże są te same pliki spakowane gzipem? Poza tym dobra odpowiedź.
enigmaticPhysicist
Tak więc chciałem dodać, że w 2020 roku wydaje się, że piodek jest najbliższą rzeczą, której szuka OP. Jest to środowisko uruchomieniowe Pythona w web assemblerze (zakładałbym, że umieść C, a następnie Python w wasm). Obsługuje również wiele bibliotek. Wydaje się też dość łatwy w użyciu.
David Frick
3

Nie będzie to możliwe, dopóki zestaw sieci Web nie zaimplementuje wyrzucania elementów bezużytecznych. Postęp możesz śledzić tutaj: https://github.com/WebAssembly/proposity/issues/16

Malcolm White
źródło
17
Niekoniecznie. Możesz zaimplementować GC - a zwłaszcza liczenie odwołań, tak jak jest używane przez Python IIRC - na wierzchu Wasm. W zasadzie powinieneś być w stanie pobrać CPython i skompilować go do Wasm przy użyciu Emscripten.
Andreas Rossberg
1
Mój wniosek z OP był taki, że chcieli użyć istniejących narzędzi - wdrożenie cpython GC na bazie wasm brzmi jak projekt sam w sobie
Malcolm White,
3
Nie powinieneś robić nic więcej, po prostu pobierz CPythona do kompilacji. Zawiera już implementację RC, AFAICT.
Andreas Rossberg
3

W skrócie: są transpilery, ale nie można automatycznie konwertować żadnego Pythona do Web Assembly i wątpię, czy będzie to możliwe przez długi czas. Chociaż teoretycznie języki są równie potężne, a ręczne tłumaczenie jest zawsze możliwe, Python pozwala na pewne struktury danych i tryby ekspresji, które wymagają bardzo inteligentnego kompilatora międzyjęzykowego (lub transpilera) [patrz poniżej]. Obejściem może być Python do C do Web Assembly, ponieważ technologia Python-to-C jest umiarkowanie dojrzała, ale generalnie nie będzie to działać, ponieważ Python-to-C jest również delikatny (patrz poniżej).

WebAssembly jest specjalnie ukierunkowana na języki podobne do C, jak widać na http://webassembly.org/docs/high-level-goals/

Tłumaczenie z Pythona na C można przeprowadzić za pomocą narzędzi takich jak PyPy, które było rozwijane przez długi czas, ale które nadal nie działa dla dowolnego kodu Pythona. Istnieje kilka powodów:

  1. Python ma kilka bardzo przydatnych, abstrakcyjnych i ładnych struktur danych, ale trudno je przetłumaczyć na statyczny kod.
  2. Python zależy od dynamicznego czyszczenia pamięci.
  3. Większość kodu Pythona zależy w dużym stopniu od różnych bibliotek, z których każda ma swoje dziwactwa i problemy (takie jak pisanie w C, a nawet w assemblerze).

Jeśli przyjrzysz się dokładniej, dlaczego Python to C (lub Python to C ++) było tak trudne, możesz zobaczyć szczegółowe powody tej zwięzłej odpowiedzi, ale myślę, że to wykracza poza zakres twojego pytania.

GregD
źródło