【问题标题】:Compiling Python to WebAssembly将 Python 编译为 WebAssembly
【发布时间】:2017-11-29 09:55:23
【问题描述】:

我已经读到可以将 Python 2.7 代码转换为 Web Assembly,但我找不到关于如何转换的权威指南。

到目前为止,我已经使用 Emscripten 及其所有必要组件将 C 程序编译为 Web Assembly,所以我知道它正在工作(使用指南:http://webassembly.org/getting-started/developers-guide/

为了在 Ubuntu 机器上执行此操作,我必须采取哪些步骤?我是否必须将 python 代码转换为 LLVM 位码,然后使用 Emscripten 进行编译?如果是这样,我将如何实现这一目标?

【问题讨论】:

标签: python emscripten webassembly


【解决方案1】:

WebAssembly 与 asm.js

首先,让我们看一下,WebAssemblyasm.js 在原则上有何不同,以及是否有可能重用现有知识和工具。下面给出了很好的概述:

让我们回顾一下,WebAssembly(MVP,its roadmap 上还有更多内容,大致):

  • 是一种具有静态类型的 AST 二进制格式,可以由现有的 JavaScript 引擎执行(因此支持 JIT 或编译的 AOT),
  • 它比 JavaScript 紧凑 10-20%(gzip 比较),解析速度快一个数量级,
  • 它可以表达更多不适合 JavaScript 语法的低级操作,读取 asm.js(例如 64 位整数、特殊 CPU 指令、SIMD 等)
  • 可(在某种程度上)与 asm.js 相互转换。

因此,目前 WebAssembly 是 asm.js 的迭代,仅针对 C/C++(和类似语言)。

网络上的 Python

看起来 GC 并不是阻止 Python 代码针对 WebAssembly/asm.js 的唯一因素。两者都代表低级静态类型代码,其中 Python 代码不能(实际上)表示。由于当前 WebAssembly/asm.js 的工具链是基于 LLVM 的,因此可以轻松编译为 LLVM IR 的语言可以转换为 WebAssembly/asm.js。但遗憾的是,Python 的动态性太大,也无法融入其中,正如 PyPy 的 Unladen Swallowseveral attempts 所证明的那样。

这个 asm.js 演示文稿有 slides about the state of dynamic languages。这意味着目前只能将整个 VM(C/C++ 中的语言实现)编译为 WebAssembly/asm.js 并解释(尽可能使用 JIT)原始源。对于 Python,有几个现有项目:

  1. PyPy:PyPy.js(作者的talk at PyCon)。这是release repo。主 JS 文件 pypyjs.vm.js 为 13 MB(gzip -6 后为 2MB)+ Python stdlib + 其他内容。

  2. CPython:pyodideEmPythonCPython-EmscriptenEmCPython 等。empython.js 为 5.8 MB(gzip -6 之后为 2.1 MB),没有标准库。

  3. 微蟒:this fork.

    那里没有构建的 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 
    

    它产生 1.1 MB 的 micropython.jsgzip -d 之后的 225 KB)。如果您只需要非常合规的实现而不需要 stdlib,则后者已经是需要考虑的问题了。

    要生成 WebAssembly 构建,您可以将 Makefile 的第 13 行更改为

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

    然后make -j 产生:

     113 KB micropython.js
     240 KB micropython.wasm
    

    您可以查看emcc hello.c -s WASM=1 -o hello.html 的 HTML 输出,了解如何使用这些文件。

    通过这种方式,您还可以在 WebAssembly 中构建 PyPy 和 CPython,以便在兼容的浏览器中解释您的 Python 应用程序。

这里另一个可能有趣的东西是Nuitka,一个 Python 到 C++ 的编译器。有可能将您的 Python 应用程序构建为 C++,然后使用 Emscripten 将其与 CPython 一起编译。但实际上我不知道该怎么做。

解决方案

目前,如果您正在构建一个传统的网站或 Web 应用程序,几乎无法下载几兆字节的 JS 文件,请查看 Python-to-JavaScript 转换器(例如 Transcrypt)或 JavaScript Python 实现(例如Brython)。或与list of languages that compile to JavaScript 的其他人一起试试运气。

否则,如果下载大小不是问题,并且您已经准备好解决很多问题,请在上述三个之间进行选择。

2020 年第三季度更新

  1. JavaScript 端口 was integrated 到 MicroPython。它住在 ports/javascript.

  2. 该端口以名为MicroPython.js 的npm 包的形式提供。 你可以在RunKit试试看。

  3. Rust 中有一个积极开发的 Python 实现,称为 RustPython。因为 Rust 官方支持WebAssembly as compile target,所以demo link 就在 自述文件的顶部。虽然,现在还早。他们的免责声明如下。

    RustPython 处于开发阶段,不应在 生产或容错设置。

    我们当前的构建只支持 Python 语法的一个子集。

【讨论】:

  • 那些 .js 和 .wasm 的大小并不公平。流压缩得到很好的支持,可用于减小两者的大小。压缩后的相同文件有多大?除此之外,很好的答案。
  • 所以想补充一点,在 2020 年,pyodide 似乎是 OP 正在寻找的最接近的东西。它是 Web 程序集中的 Python 运行时(我假设先将 C 和 Python 放入 wasm)。它也支持多个库。此外,似乎很容易使用。
  • 所以我不能使用 Pyodide 通过 WebAssembly 创建 WebApp?我想使用 Flask 作为后端
  • 另外一个用 rust 编写的 python 解释器有什么用
  • @HaMAD 之所以使用是因为 Rust 对编译到 WASM 有很好的支持,这意味着您可以将 Python 的 Rust 端口编译为 WASM。您也可以将 C 程序编译为 WASM,但我不确定让它工作起来有多好。
【解决方案2】:

简而言之:有转译器,但您不能自动将任意 Python 转换为 Web Assembly,而且我怀疑您能否在很长一段时间内做到这一点。尽管理论上这些语言同样强大,而且手动翻译总是可能的,但 Python 允许一些数据结构和表达模式,这需要非常智能的跨语言编译器(或转译器)[见下文]。一种解决方法可能是 Python 到 C 到 Web 程序集,因为 Python 到 C 技术已经相当成熟,但这通常也不起作用,因为 Python 到 C 也很脆弱(见下文)。

WebAssembly 专门针对类 C 语言,您可以在 http://webassembly.org/docs/high-level-goals/ 看到这一点

可以使用 PyPy 等工具完成从 Python 到 C 的翻译,该工具已经开发了很长时间,但仍然不适用于任意 Python 代码。这有几个原因:

  1. Python 有一些非常方便、抽象和漂亮的数据结构,但它们很难转换成静态代码。
  2. Python 依赖于动态垃圾回收。
  3. 大多数 Python 代码严重依赖于各种库,每个库都有自己的怪癖和问题(例如用 C 编写,甚至是汇编程序)。

如果您更仔细地研究为什么 Python 到 C(或 Python 到 C++)如此棘手,您可以看到这个简洁答案背后的详细原因,但我认为这超出了您的问题范围。

【讨论】:

    【解决方案3】:

    在 Web 程序集实现垃圾收集之前,这是不可能的。您可以在这里关注进度:https://github.com/WebAssembly/proposals/issues/16

    【讨论】:

    • 不一定。您可以在 Wasm 之上实现 GC——尤其是引用计数,因为它被 Python IIRC 使用。原则上,您应该能够使用 CPython 并使用 Emscripten 将其编译为 Wasm。
    • 我对 OP 的看法是,他们想使用现有的工具——在 wasm 之上实现 cpython GC 听起来像是一个项目本身
    • 您不必做任何额外的事情,只需让 CPython 编译即可。它已经包含了 RC 实现,AFAICT。
    【解决方案4】:

    我首先想到的是PyPy和rpython,然后我发现

    https://github.com/soIu/rpython

    我们无法将任意 python 代码转换为 rpython。但是,如果您需要替代语言而不是 rust 或 AssemblyScript,rpython 可能是一个方向。

    因此,我可以将 python/js/rust 与 wasm 一起用作沙箱,并使用非常 Python 的语言(例如 rpython)进行编码。至少我不用担心整数溢出。

    【讨论】:

      猜你喜欢
      • 2018-03-16
      • 2022-01-25
      • 1970-01-01
      • 1970-01-01
      • 2017-12-22
      • 1970-01-01
      • 2019-08-24
      • 2019-02-14
      • 1970-01-01
      相关资源
      最近更新 更多