119

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

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

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

4

4 回答 4

183

WebAssembly 与 asm.js

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

让我们概括一下,WebAssembly(MVP,因为它的路线图上还有更多内容,粗略):

  • 是一种具有静态类型的 AST 二进制格式,可以由现有的 JavaScript 引擎执行(因此可以执行 JIT 或编译的 AOT),
  • 它比 JavaScript 紧凑 10-20%(gzipped 比较)并且解析速度快一个数量级,
  • 它可以表达更多不适合 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 的动态性太大,无法融入其中,Unladen Swallow和PyPy 的几次尝试都证明了这一点。

这个 asm.js 演示文稿有关于动态语言状态的幻灯片。这意味着目前只能将整个 VM(C/C++ 中的语言实现)编译为 WebAssembly/asm.js 并解释(尽可能使用 JIT)原始源。对于 Python,有几个现有项目:

  1. PyPy:PyPy.js(作者在 PyCon 的演讲)。这是发布回购。主 JS 文件pypyjs.vm.js13 MB(之后 2MB gzip -6)+ Python stdlib + 其他东西。

  2. CPython:pyodideEmPythonCPython-EmscriptenEmCPythonempython.js为 5.8 MB(之后为 2.1 MB gzip -6),没有 stdlib。

  3. Micropython:这个 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 
    

    它产生micropython.js1.1 MB(之后为 225 KB 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,了解如何使用这些文件。

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

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

解决方案

目前,如果您正在构建一个传统的网站或 Web 应用程序,下载几兆字节的 JS 文件几乎是不可能的,请查看 Python 到 JavaScript 的转译器(例如 Transcrypt 或 JavaScript Python 实现(例如Brython)。或者从编译为 JavaScript 的语言列表中与其他人一起试试运气。

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

2020 年第三季度更新

  1. JavaScript 端口被集成到 MicroPython 中。它位于 ports/javascript中。

  2. 该端口以名为MicroPython.js的 npm 包的形式提供。您可以在RunKit中尝试一下。

  3. Rust 中有一个积极开发的 Python 实现,称为 RustPython。因为 Rust 官方支持WebAssembly 作为编译目标,所以在自述文件的顶部有演示链接也就不足为奇了。虽然,现在还早。他们的免责声明如下。

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

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

于 2017-12-10T13:53:23.570 回答
8

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

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

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

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

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

于 2017-12-10T21:42:29.647 回答
3

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

于 2017-07-15T01:41:12.643 回答
0

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

https://github.com/soIu/rpython

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

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

于 2021-11-06T15:09:52.293 回答