Компиляция Python в WebAssembly

90

Я читал, что можно преобразовать код Python 2.7 в веб-сборку, но я не могу найти подробного руководства о том, как это сделать.

До сих пор я скомпилировал программу C для веб-сборки с использованием Emscripten и всех его необходимых компонентов, поэтому я знаю, что она работает (используемое руководство: http://webassembly.org/getting-started/developers-guide/ )

Какие шаги я должен предпринять, чтобы сделать это на машине Ubuntu? Нужно ли мне преобразовывать код Python в битовый код LLVM, а затем скомпилировать его с помощью Emscripten? Если да, то как мне этого добиться?

Робби
источник
1
@guettli github.com/pypyjs/pyjs/issues/145
denfromufa
1
Проверьте pyodide: hacks.mozilla.org/2019/04/…
Alex
1
Pyodide переносит среду выполнения Python в браузер через WebAssembly: github.com/iodide-project/pyodide
guettli

Ответы:

146

WebAssembly против asm.js

Во-первых, давайте посмотрим, чем в принципе WebAssembly отличается от asm.js и есть ли возможность повторно использовать существующие знания и инструменты. Следующее дает довольно хороший обзор:

Подведем итоги, WebAssembly ( примерно MVP, поскольку в его дорожной карте есть больше ):

  • представляет собой двоичный формат AST со статической типизацией, который может выполняться существующими механизмами JavaScript (и, таким образом, JIT-совместимым или скомпилированным AOT),
  • он на 10-20% компактнее (сравнение с сжатием) и на порядок быстрее разбирается, чем JavaScript,
  • он может выражать более низкоуровневую операцию, которая не вписывается в синтаксис JavaScript, читать asm.js (например, 64-битные целые числа, специальные инструкции ЦП, SIMD и т. д.)
  • конвертируется (до некоторой степени) в / из asm.js.

Таким образом, в настоящее время WebAssembly представляет собой итерацию asm.js и нацелен только на C / C ++ (и аналогичные языки).

Python в сети

Не похоже, что сборщик мусора - единственное, что мешает коду Python нацеливаться на WebAssembly / asm.js. Оба представляют собой низкоуровневый статически типизированный код, в котором код Python не может (реалистично) быть представлен. Поскольку текущий набор инструментов WebAssembly / asm.js основан на LLVM, язык, который можно легко скомпилировать в LLVM IR, можно преобразовать в WebAssembly / asm.js. Но, увы, Python слишком динамичен, чтобы вписаться в него, что было доказано Unladen Swallow и несколькими попытками PyPy.

В этой презентации asm.js есть слайды о состоянии динамических языков . Это означает, что в настоящее время можно скомпилировать только виртуальную машину целиком (языковая реализация на C / C ++) в WebAssembly / asm.js и интерпретировать (при возможности с JIT) исходные коды. Для Python существует несколько существующих проектов:

  1. PyPy: PyPy.js ( доклад автора на PyCon ). Вот репо релиза . Основной JS-файл pypyjs.vm.jsимеет gzip -6размер 13 МБ (после 2 МБ ) + Python stdlib + другие вещи.

  2. CPython: pyodide , EmPython , CPython-Emscripten , EmCPython и т. Д. Составляетempython.js 5,8 МБ (после 2,1 МБ gzip -6), stdlib отсутствует.

  3. Micropython: эта вилка .

    Там не было встроенного файла JS, поэтому я смог собрать его с trzeci/emscripten/помощью готовой цепочки инструментов Emscripten. Что-то типа:

     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.js1,1 МБ (после 225 КБ gzip -d). Последнее уже следует учитывать, если вам нужна только очень совместимая реализация без stdlib.

    Чтобы создать сборку WebAssembly, вы можете изменить строку 13 файла Makefileна

     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 файл является едва ли вариант, посмотрите на Python-к-JavaScript transpilers (например Transcrypt ) или реализации JavaScript Python (например бритт ). Или испытайте удачу с другими из списка языков, которые компилируются в JavaScript .

В противном случае, если размер загружаемого файла не является проблемой, и вы готовы решить множество проблем, выберите один из трех указанных выше.

Обновление Q3 2020

  1. Порт JavaScript был интегрирован в MicroPython. Он живет в портах / javascript .

  2. Порт доступен в виде пакета npm под названием MicroPython.js . Вы можете попробовать это в RunKit .

  3. В Rust есть активно разрабатываемая реализация Python под названием RustPython . Поскольку Rust официально поддерживает WebAssembly в качестве цели компиляции , неудивительно, что прямо в верхней части файла readme есть демонстрационная ссылка . Хотя еще рано. Их отказ от ответственности следует.

    RustPython находится в стадии разработки и не должен использоваться в продакшене или в настройках, допускающих ошибки.

    Наша текущая сборка поддерживает только подмножество синтаксиса Python.

Saaj
источник
1
Эти размеры .js и .wasm не совсем справедливы. Сжатие потока хорошо поддерживается и может использоваться для уменьшения размера обоих. Насколько велики те же файлы в сжатом виде? Кроме этого, хороший ответ.
enigmaticPhysicist
Поэтому хотел добавить, что в 2020 году пиодид - это самое близкое, что ищет OP. Это среда выполнения Python в веб-сборке (я бы предположил, что C, а затем Python в wasm). Он также поддерживает несколько библиотек. Кроме того, кажется достаточно простым в использовании.
Дэвид Фрик,
3

Это будет невозможно, пока веб-сборка не реализует сборку мусора. Вы можете следить за прогрессом здесь: https://github.com/WebAssembly/proposals/issues/16

Малькольм Уайт
источник
17
Не обязательно. Вы можете реализовать сборщик мусора - и особенно подсчет ссылок, как он используется в Python IIRC - поверх Wasm. В принципе, у вас должна быть возможность взять CPython и скомпилировать его в Wasm с помощью Emscripten.
Андреас Россберг
1
Мое мнение от OP заключалось в том, что они хотели использовать существующие инструменты - реализация cpython GC поверх wasm сама по себе звучит как проект,
Малкольм Уайт
3
Вам не нужно делать ничего лишнего, просто скомпилируйте CPython. Он уже содержит реализацию RC AFAICT.
Андреас Россберг
3

Вкратце: существуют транспилеры, но вы не можете автоматически преобразовать любой произвольный Python в веб-сборку, и я сомневаюсь, что вы сможете это сделать еще долго. Хотя теоретически языки одинаково мощны, и всегда возможен ручной перевод, Python допускает некоторые структуры данных и выразительные режимы, которые требуют очень умного межъязыкового компилятора (или транспилятора) [см. Ниже]. Обходным путем может быть переход от Python к C к веб-сборке, поскольку технология 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 to C ++) оказался таким сложным, вы можете увидеть подробные причины этого краткого ответа, но я думаю, что это выходит за рамки вашего вопроса.

GregD
источник