การรวบรวม Python ไปยัง WebAssembly


95

ฉันได้อ่านพบว่าเป็นไปได้ที่จะแปลงรหัส Python 2.7 เป็น Web Assembly แต่ฉันไม่พบคำแนะนำที่ชัดเจนเกี่ยวกับวิธีการดังกล่าว

จนถึงตอนนี้ฉันได้รวบรวมโปรแกรม C ไปยัง Web Assembly โดยใช้ Emscripten และส่วนประกอบที่จำเป็นทั้งหมดดังนั้นฉันจึงรู้ว่ามันใช้งานได้ (คำแนะนำที่ใช้: http://webassembly.org/getting-started/developers-guide/ )

ฉันต้องทำขั้นตอนใดบ้างเพื่อทำสิ่งนี้บนเครื่อง Ubuntu ฉันต้องแปลงรหัส python เป็น LLVM bitcode แล้วคอมไพล์โดยใช้ Emscripten หรือไม่ ถ้าเป็นเช่นนั้นฉันจะบรรลุเป้าหมายนี้ได้อย่างไร?



1
ตรวจสอบpyodide: hacks.mozilla.org/2019/04/…
Alex

1
Pyodide นำรันไทม์ Python ไปยังเบราว์เซอร์ผ่าน WebAssembly: github.com/iodide-project/pyodide
guettli

คำตอบ:


149

WebAssembly กับ asm.js

ก่อนอื่นมาดูกันว่าโดยหลักการแล้วWebAssemblyแตกต่างจากasm.jsอย่างไรและมีศักยภาพที่จะนำความรู้และเครื่องมือที่มีอยู่กลับมาใช้ใหม่ได้หรือไม่ ข้อมูลต่อไปนี้ให้ภาพรวมที่ค่อนข้างดี:

มาสรุปกันใหม่ WebAssembly (MVP เนื่องจากมีข้อมูลเพิ่มเติมเกี่ยวกับแผนงานโดยประมาณ):

  • เป็นรูปแบบไบนารีของ AST ที่มีการพิมพ์แบบคงที่ซึ่งสามารถดำเนินการได้โดยเอ็นจิ้น JavaScript ที่มีอยู่ (และทำให้ JIT สามารถหรือคอมไพล์ AOT ได้)
  • มีขนาดกะทัดรัดกว่า 10-20% (การเปรียบเทียบแบบ gzipped) และลำดับความสำคัญในการแยกวิเคราะห์เร็วกว่า JavaScript
  • สามารถแสดงการทำงานในระดับต่ำมากขึ้นซึ่งไม่พอดีกับไวยากรณ์ของ JavaScript อ่าน asm.js (เช่นจำนวนเต็ม 64 บิตคำแนะนำพิเศษของ CPU SIMD ฯลฯ )
  • สามารถเปลี่ยนแปลงได้ (ในบางส่วน) ถึง / จาก asm.js

ดังนั้นปัจจุบัน WebAssembly เป็นการทำซ้ำบน asm.js และกำหนดเป้าหมายเฉพาะ C / C ++ (และภาษาที่คล้ายกัน)

Python บนเว็บ

ดูเหมือนว่า GC จะไม่เป็นสิ่งเดียวที่หยุดโค้ด Python จากการกำหนดเป้าหมาย WebAssembly / asm.js ทั้งสองเป็นตัวแทนของรหัสที่พิมพ์แบบคงที่ระดับต่ำซึ่งโค้ด Python ไม่สามารถแสดงได้ (ตามความเป็นจริง) เนื่องจาก toolchain ปัจจุบันของ WebAssembly / asm.js ใช้ LLVM ภาษาที่สามารถคอมไพล์เป็น LLVM IR ได้อย่างง่ายดายจึงสามารถแปลงเป็น WebAssembly / asm.js แต่อนิจจา Python มีไดนามิกเกินกว่าที่จะใส่เข้าไปได้เช่นกันซึ่งพิสูจน์แล้วโดยUnladen Swallowและความพยายามหลายครั้งของ PyPy

นำเสนอ asm.js นี้มีภาพนิ่งเกี่ยวกับสถานะของภาษาแบบไดนามิก ความหมายคือขณะนี้สามารถรวบรวม VM ทั้งหมด (การใช้ภาษาใน C / C ++) ไปยัง WebAssembly / asm.js และตีความ (ด้วย JIT หากเป็นไปได้) ต้นฉบับ สำหรับ Python มีหลายโครงการที่มีอยู่:

  1. PyPy: PyPy.js (ผู้เขียนพูดคุยที่ PyCon ) นี่คือการเปิดตัว repo ไฟล์ JS หลักpypyjs.vm.jsคือ 13 MB (หลัง 2MB gzip -6) + Python stdlib + สิ่งอื่น ๆ

  2. CPython: pyodide , EmPython , CPython-Emscripten , EmCPythonฯลฯempython.jsคือ 5.8 MB (หลัง 2.1 MB gzip -6) ไม่มี stdlib

  3. Micropython: ส้อมนี้

    ไม่มีไฟล์ JS ที่สร้างขึ้นที่นั่นดังนั้นฉันจึงสามารถสร้างมันด้วยtrzeci/emscripten/Emscripten toolchain สำเร็จรูป สิ่งที่ต้องการ:

     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 
    

    มีmicropython.jsขนาด 1.1 MB (225 KB หลังgzip -d) สิ่งหลังนี้เป็นสิ่งที่ต้องพิจารณาหากคุณต้องการเพียงการใช้งานที่สอดคล้องกับมาตรฐานโดยไม่ต้องใช้ stdlib

    ในการสร้าง WebAssembly คุณสามารถเปลี่ยนบรรทัดที่ 13 ของMakefileto

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

    จากนั้นmake -jผลิต:

     113 KB micropython.js
     240 KB micropython.wasm
    

    คุณสามารถดูผลลัพธ์ HTML ของemcc hello.c -s WASM=1 -o hello.htmlเพื่อดูวิธีใช้ไฟล์เหล่านี้

    ด้วยวิธีนี้คุณสามารถสร้าง PyPy และ CPython ใน WebAssembly เพื่อตีความแอปพลิเคชัน Python ของคุณในเบราว์เซอร์ที่เข้ากันได้

สิ่งที่น่าสนใจอีกอย่างที่นี่คือNuitkaซึ่งเป็นคอมไพเลอร์ Python ถึง C ++ อาจเป็นไปได้ที่จะสร้างแอพ Python ของคุณเป็น C ++ แล้วคอมไพล์พร้อมกับ CPython ด้วย Emscripten แต่ในทางปฏิบัติฉันไม่รู้ว่าจะทำอย่างไร

แนวทางแก้ไข

ในขณะนี้หากคุณกำลังสร้างเว็บไซต์หรือเว็บแอปทั่วไปที่ดาวน์โหลดไฟล์ JS ขนาดหลายเมกะไบต์แทบจะไม่มีตัวเลือกให้ดูที่Transcrypt -to-JavaScript (เช่นTranscrypt ) หรือการใช้งาน JavaScript Python (เช่นBrython ). หรือลองโชคของคุณกับคนอื่น ๆ จากรายการภาษาที่รวบรวม JavaScript

มิฉะนั้นหากขนาดการดาวน์โหลดไม่ใช่ปัญหาและคุณพร้อมที่จะจัดการกับขอบหยาบจำนวนมากให้เลือกระหว่างสามข้อด้านบน

การอัปเดต Q3 2020

  1. พอร์ต JavaScript ถูกรวมเข้ากับ MicroPython มันอาศัยอยู่ใน พอร์ต javascript /

  2. พอร์ตสามารถใช้ได้เป็นแพคเกจที่เรียกว่า NPM MicroPython.js คุณสามารถลองมันออกมาในRunKit

  3. มีการดำเนินการหลามพัฒนาอย่างแข็งขันใน Rust ที่เรียกว่า RustPython เนื่องจาก Rust สนับสนุนWebAssembly เป็นเป้าหมายการคอมไพล์อย่างเป็นทางการจึงไม่ต้องแปลกใจเลยว่ามีลิงก์สาธิตอยู่ด้านบนสุดของ readme แม้ว่าจะยังเร็วอยู่ คำปฏิเสธของพวกเขาดังต่อไปนี้

    RustPython อยู่ในขั้นตอนการพัฒนาและไม่ควรใช้ในการผลิตหรือการตั้งค่าที่ทนต่อความผิดพลาด

    บิลด์ปัจจุบันของเรารองรับไวยากรณ์ Python เพียงบางส่วนเท่านั้น


2
ขนาด. js และ. wasm นั้นไม่ยุติธรรมจริงๆ การบีบอัดสตรีมได้รับการสนับสนุนอย่างดีและสามารถใช้เพื่อลดขนาดของทั้งสองอย่างได้ ไฟล์เดียวกันมีขนาดใหญ่แค่ไหน? นอกเหนือจากนั้นคำตอบที่ดี
enigmaticPhysicist

ดังนั้นต้องการเพิ่มว่าในปี 2020 ดูเหมือนว่า pyodide จะเป็นสิ่งที่ OP กำลังมองหามากที่สุด มันคือรันไทม์ Python ใน web assembly (ฉันจะถือว่าใส่ C แล้ว Python เป็น wasm) รองรับหลายไลบรารีเช่นกัน นอกจากนี้ดูเหมือนง่ายพอที่จะใช้
David Frick

3

สิ่งนี้จะไม่สามารถทำได้จนกว่า Web Assembly จะดำเนินการรวบรวมขยะ ติดตามความคืบหน้าได้ที่นี่: https://github.com/WebAssembly/proposals/issues/16


18
ไม่จำเป็น. คุณสามารถใช้ GC - และโดยเฉพาะอย่างยิ่งการนับอ้างอิงตามที่ Python IIRC ใช้อยู่ด้านบนของ Wasm โดยหลักการแล้วคุณควรจะสามารถใช้ CPython และรวบรวมเป็น Wasm โดยใช้ Emscripten
Andreas Rossberg

1
สิ่งที่ฉันใช้จาก OP คือพวกเขาต้องการใช้เครื่องมือที่มีอยู่ - การนำ cpython GC ไปใช้กับ wasm ดูเหมือนเป็นโครงการในตัวเอง
Malcolm White

3
คุณไม่ต้องทำอะไรเพิ่มเติมเพียงแค่รับ CPython เพื่อรวบรวม มีการใช้งาน RC AFAICT อยู่แล้ว
Andreas Rossberg

3

กล่าวโดยย่อ: มี Transpiler แต่คุณไม่สามารถแปลง Python ใด ๆ โดยพลการเป็น Web Assembly ได้โดยอัตโนมัติและฉันสงสัยว่าคุณจะสามารถทำได้ในอีกนาน แม้ว่าในทางทฤษฎีภาษาจะมีประสิทธิภาพเท่าเทียมกันและการแปลด้วยตนเองก็ทำได้ตลอดเวลา Python อนุญาตให้มีโครงสร้างข้อมูลและโหมดการแสดงออกบางอย่างที่ต้องใช้คอมไพเลอร์ระหว่างภาษาที่ชาญฉลาดมาก (หรือทรานสไพเลอร์) [ดูด้านล่าง] วิธีแก้ปัญหาอาจเป็น Python to C to Web Assembly เนื่องจากเทคโนโลยี python-to-C มีความสมบูรณ์พอสมควร แต่โดยทั่วไปจะไม่ได้ผลเนื่องจาก Python-to-C นั้นบอบบางเช่นกัน (ดูด้านล่าง)

WebAssembly มีเป้าหมายเฉพาะสำหรับภาษาที่คล้าย C ดังที่คุณเห็นที่http://webassembly.org/docs/high-level-goals/

การแปลจาก Python เป็น C สามารถทำได้ด้วยเครื่องมือเช่น PyPy ซึ่งอยู่ระหว่างการพัฒนามาเป็นเวลานาน แต่ยังใช้ไม่ได้กับรหัส Python ที่กำหนดเอง มีหลายเหตุผลนี้:

  1. Python มีโครงสร้างข้อมูลที่มีประโยชน์นามธรรมและสวยงาม แต่ยากที่จะแปลเป็นรหัสคงที่
  2. Python ขึ้นอยู่กับการรวบรวมขยะแบบไดนามิก
  3. รหัส Python ส่วนใหญ่ขึ้นอยู่กับไลบรารีต่างๆเป็นอย่างมากซึ่งแต่ละรายการมีนิสัยใจคอและปัญหาของตัวเอง (เช่นเขียนด้วย C หรือแม้แต่แอสเซมเบลอร์

หากคุณพิจารณาอย่างรอบคอบมากขึ้นว่าเหตุใด Python-to-C (หรือ Python ถึง C ++) จึงยุ่งยากมากคุณสามารถดูเหตุผลโดยละเอียดที่อยู่เบื้องหลังคำตอบสั้น ๆ นี้ได้ แต่ฉันคิดว่ามันอยู่นอกขอบเขตของคำถาม

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.