将Python编译为WebAssembly


90

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

到目前为止,我已经使用Emscripten及其所有必需的组件将C程序编译为Web程序,因此我知道它是有效的(使用的指南:http : //webassembly.org/getting-started/developers-guide/

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




1
Pyodide通过WebAssembly将Python运行时引入浏览器:github.com/iodide-project/pyodide
guettli

Answers:


146

WebAssembly与asm.js

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

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

  • 是具有静态类型的AST的二进制格式,可以由现有的JavaScript引擎(因此可以通过JIT或已编译的AOT执行)执行,
  • 它比JavaScript压缩了10-20%(压缩比较),解析速度快了一个数量级,
  • 它可以表达不适合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。但是可惜,正如Unladen Swallow和PyPy的多次尝试所证明的那样,Python太动态了,无法适应它。

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

  1. PyPy:PyPy.js在PyCon上的作者演讲)。这是发行回购。JS主文件pypyjs.vm.js为13 MB(后面为2MB gzip -6)+ Python stdlib +其他内容。

  2. CPython:pyodideEmPythonCPython-EmscriptenEmCPythonempython.js为5.8 MB(后为2.1 MB 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.js为1.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一起编译。但是实际上我不知道该怎么做。

解决方案

暂时,如果你正在建设一个传统的网站或网络应用程序,其中下载数兆字节的JS文件仅仅是一个选项,看看的Python到JavaScript transpilers(如Transcrypt)或JavaScript Python实现(例如Brython)。或者尝试从编译为JavaScript的语言列表中与其他人合作

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

2020年第三季度更新

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

  2. 该端口可通过名为MicroPython.js的npm软件包获得。您可以在RunKit中尝试一下。

  3. 在Rust中有一个积极开发的Python实现,称为 RustPython。由于Rust正式支持WebAssembly作为编译目标,因此自述文件顶部便有演示链接。不过,还早。他们的免责声明如下。

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

    我们当前的版本仅支持Python语法的子集。


1
那些.js和.wasm的大小并不公平。流压缩得到了很好的支持,可以用来减小两者的大小。压缩后的相同文件有多大?除此之外,好的答案。
enigmaticPhysicist

因此想补充一下,在2020年,似乎pyodide是OP寻找的最接近的东西。它是Web汇编中的Python运行时(我假设将C然后放在Python中放入wasm)。它也支持多个库。此外,似乎很容易使用。
David Frick

3

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


17
不必要。您可以在Wasm之上实现GC(尤其是Python IIRC使用的引用计数)。原则上,您应该能够使用CPython并使用Emscripten将其编译为Wasm。
安德烈亚斯·罗斯伯格

1
我采取从OP是,他们希望使用现有的工具-实施CPython的GC上WASM声音的顶部像本身就是一个项目
马尔科姆·怀特

3
您不必做任何额外的工作,只需编译CPython。它已经包含了RC实施AFAICT。
安德里亚斯·罗斯伯格

3

简而言之:有编译器,但是您不能自动将任意Python转换为Web Assembly,并且我怀疑您将能够在很长一段时间内使用它。尽管从理论上讲这些语言具有同等强大的功能,并且始终可以进行手动翻译,但是Python允许某些数据结构和表达模式,它们需要非常聪明的跨语言编译器(或翻译器)[请参见下文]。解决方法可能是从Python到C到Web组装,因为python-to-C技术已经相当成熟,但由于Python-to-C也很脆弱,因此通常也不起作用(请参见下文)。

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

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

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

如果您更仔细地研究为什么Python到C(或Python到C ++)如此棘手,您会看到此简短答案背后的详细原因,但我认为这不在您的问题范围内。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.