Mengompilasi Python ke WebAssembly

90

Saya telah membaca bahwa dimungkinkan untuk mengubah kode Python 2.7 ke Web Assembly, tetapi saya tidak dapat menemukan panduan pasti tentang cara melakukannya.

Sejauh ini saya telah menyusun program C ke Web Assembly menggunakan Emscripten dan semua komponen yang diperlukan, jadi saya tahu itu berfungsi (panduan yang digunakan: http://webassembly.org/getting-started/developers-guide/ )

Apa langkah-langkah yang harus saya ambil untuk melakukan ini di mesin Ubuntu? Apakah saya harus mengubah kode python menjadi LLVM bitcode kemudian mengkompilasinya menggunakan Emscripten? Jika demikian, bagaimana saya mencapai ini?

Robbie
sumber
1
@guettli github.com/pypyjs/pypyjs/issues/145
denfromufa
1
Lihat pyodide: hacks.mozilla.org/2019/04/…
Alex
1
Pyodide menghadirkan runtime Python ke browser melalui WebAssembly: github.com/iodide-project/pyodide
guettli

Jawaban:

146

WebAssembly vs asm.js

Pertama, mari kita lihat bagaimana, pada prinsipnya, WebAssembly berbeda dari asm.js , dan apakah ada potensi untuk menggunakan kembali pengetahuan dan perkakas yang ada. Berikut ini memberikan gambaran umum yang cukup bagus:

Mari kita rekapitulasi, WebAssembly (MVP, karena ada lebih banyak tentang peta jalannya , secara kasar):

  • adalah format biner AST dengan pengetikan statis, yang dapat dijalankan oleh mesin JavaScript yang ada (dan dengan demikian dapat JIT atau AOT yang dikompilasi),
  • ini 10-20% lebih ringkas (perbandingan gzip) dan urutan besarnya lebih cepat untuk diurai daripada JavaScript,
  • itu dapat mengekspresikan lebih banyak operasi tingkat rendah yang tidak sesuai dengan sintaks JavaScript, baca asm.js (misalnya bilangan bulat 64-bit, instruksi CPU khusus, SIMD, dll)
  • dapat dikonversi (sampai batas tertentu) ke / dari asm.js.

Jadi, saat ini WebAssembly merupakan iterasi pada asm.js dan hanya menargetkan C / C ++ (dan bahasa serupa).

Python di Web

Sepertinya GC bukanlah satu-satunya hal yang menghentikan kode Python untuk menargetkan WebAssembly / asm.js. Keduanya mewakili kode yang diketik secara statis tingkat rendah, di mana kode Python tidak dapat (secara realistis) diwakili. Karena rantai alat WebAssembly / asm.js saat ini didasarkan pada LLVM, bahasa yang dapat dengan mudah dikompilasi ke LLVM IR dapat diubah menjadi WebAssembly / asm.js. Namun sayang, Python terlalu dinamis untuk menyesuaikannya juga, seperti yang dibuktikan oleh Unladen Swallow dan beberapa percobaan PyPy.

Presentasi asm.js ini memiliki slide tentang status bahasa dinamis . Artinya, saat ini hanya mungkin untuk mengkompilasi seluruh VM (implementasi bahasa dalam C / C ++) ke WebAssembly / asm.js dan menafsirkan (dengan JIT jika memungkinkan) sumber asli. Untuk Python, ada beberapa proyek yang sudah ada:

  1. PyPy: PyPy.js ( ceramah penulis di PyCon ). Berikut rilis repo . File JS utama pypyjs.vm.js,, berukuran 13 MB (2MB setelahnya gzip -6) + Python stdlib + hal lainnya.

  2. CPython: pyodide , EmPython , CPython-Emscripten , EmCPython , dll. Berukuranempython.js 5,8 MB (2,1 MB setelahnya gzip -6), tidak ada stdlib.

  3. Micropython: garpu ini .

    Tidak ada file JS yang dibuat di sana, jadi saya bisa membuatnya dengan trzeci/emscripten/, toolchain Emscripten yang sudah jadi. Sesuatu seperti:

     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 
    

    Ini menghasilkan micropython.js1,1 MB (225 KB setelah gzip -d). Yang terakhir ini sudah menjadi pertimbangan, jika Anda hanya membutuhkan implementasi yang sangat patuh tanpa stdlib.

    Untuk menghasilkan build WebAssembly Anda dapat mengubah baris 13 dari Makefilemenjadi

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

    Kemudian make -jmenghasilkan:

     113 KB micropython.js
     240 KB micropython.wasm
    

    Anda dapat melihat keluaran HTML emcc hello.c -s WASM=1 -o hello.html, untuk melihat bagaimana menggunakan file-file ini.

    Dengan cara ini Anda juga berpotensi membangun PyPy dan CPython di WebAssembly untuk menafsirkan aplikasi Python Anda di browser yang sesuai.

Hal lain yang berpotensi menarik di sini adalah Nuitka , kompiler Python ke C ++. Secara potensial dimungkinkan untuk membangun aplikasi Python Anda ke C ++ dan kemudian mengkompilasinya bersama CPython dengan Emscripten. Tapi secara praktis saya tidak tahu bagaimana melakukannya.

Solusi

Untuk saat ini, jika Anda membangun situs web atau aplikasi web konvensional di mana mengunduh file JS beberapa megabyte hampir tidak ada pilihan lain, lihat transpiler Python-to-JavaScript ( mis.Transcrypt ) atau implementasi JavaScript Python (mis. Brython ). Atau coba keberuntungan Anda dengan orang lain dari daftar bahasa yang dikompilasi ke JavaScript .

Jika tidak, jika ukuran unduhan tidak menjadi masalah, dan Anda siap untuk mengatasi banyak kesulitan, pilih di antara tiga di atas.

Pembaruan Q3 2020

  1. Port JavaScript diintegrasikan ke MicroPython. Itu tinggal di port / javascript .

  2. Porta ini tersedia sebagai paket npm yang disebut MicroPython.js . Anda dapat mencobanya di RunKit .

  3. Ada implementasi Python yang dikembangkan secara aktif di Rust, yang disebut RustPython . Karena Rust secara resmi mendukung WebAssembly sebagai target kompilasi , tidak heran ada tautan demo tepat di bagian atas readme. Padahal, ini masih dini. Penafian mereka mengikuti.

    RustPython sedang dalam fase pengembangan dan tidak boleh digunakan dalam produksi atau pengaturan yang tidak toleran terhadap kesalahan.

    Build kami saat ini hanya mendukung subset sintaks Python.

saaj
sumber
1
Ukuran .js dan .wasm itu tidak benar-benar adil. Kompresi aliran didukung dengan baik dan dapat digunakan untuk mengurangi ukuran keduanya. Seberapa besar file yang sama, dalam format gzip? Selain itu, jawaban yang bagus.
enigmaticPhysicist
Jadi ingin menambahkan bahwa di tahun 2020, sepertinya pyodide adalah hal terdekat yang dicari OP. Ini adalah runtime Python dalam perakitan web (saya akan berasumsi menempatkan C dan kemudian Python menjadi wasm). Ini mendukung banyak perpustakaan juga. Juga, sepertinya cukup mudah digunakan.
David Frick
3

Ini tidak akan mungkin sampai perakitan web menerapkan pengumpulan sampah. Anda dapat mengikuti kemajuannya di sini: https://github.com/WebAssembly/proposals/issues/16

Malcolm White
sumber
17
Belum tentu. Anda dapat menerapkan GC - dan terutama penghitungan referensi, seperti yang digunakan oleh Python IIRC - di atas Wasm. Pada prinsipnya, Anda harus dapat mengambil CPython dan mengkompilasinya ke Wasm menggunakan Emscripten.
Andreas Rossberg
1
Saya mengambil dari OP adalah bahwa mereka ingin menggunakan alat yang ada - menerapkan GC cpython di atas wasm terdengar seperti proyek itu sendiri
Malcolm White
3
Anda tidak perlu melakukan sesuatu yang ekstra, cukup dapatkan CPython untuk dikompilasi. Itu sudah berisi implementasi RC, AFAICT.
Andreas Rossberg
3

Singkatnya: Ada transpiler, tetapi Anda tidak dapat secara otomatis mengonversi Python sembarang ke Web Assembly, dan saya ragu Anda akan bisa melakukannya untuk waktu yang lama. Meskipun secara teoritis bahasanya sama kuatnya, dan terjemahan manual selalu dimungkinkan, Python memungkinkan untuk beberapa struktur data dan mode ekspresif yang membutuhkan kompiler antar-bahasa (atau transpiler) yang sangat cerdas [lihat di bawah]. Solusinya mungkin Python ke C to Web Assembly karena teknologi python-to-C cukup matang, tetapi itu umumnya tidak akan berhasil karena Python-to-C juga rapuh (lihat di bawah).

WebAssembly secara khusus ditargetkan ke bahasa mirip C seperti yang Anda lihat di http://webassembly.org/docs/high-level-goals/

Menerjemahkan dari Python ke C dapat dilakukan dengan alat seperti PyPy, yang telah dikembangkan untuk waktu yang lama, tetapi masih tidak berfungsi untuk kode sembarang Python. Ada beberapa alasan untuk ini:

  1. Python memiliki beberapa struktur data yang sangat berguna, abstrak dan bagus, tetapi sulit untuk diterjemahkan ke dalam kode statis.
  2. Python bergantung pada pengumpulan sampah dinamis.
  3. Kebanyakan kode Python sangat bergantung pada berbagai pustaka, yang masing-masing memiliki kebiasaan dan masalah sendiri (seperti ditulis dalam C, atau bahkan assembler).

Jika Anda melihat lebih teliti mengapa Python-to-C (atau Python ke C ++) begitu rumit, Anda dapat melihat alasan terperinci di balik jawaban singkat ini, tetapi saya pikir itu di luar cakupan pertanyaan Anda.

GregD
sumber