WebAssembly vs asm.js
首先,让我们看一下原则上WebAssembly与asm.js有何不同,以及是否有可能重用现有的知识和工具。以下内容提供了很好的概述:
让我们回顾一下,WebAssembly(MVP,因为在其路线图中还有更多):
- WebAssembly是一种具有静态类型的AST二进制格式,可以在现有JavaScript引擎上执行(因此可以JIT编译或AOT编译),
- 它比JavaScript更紧凑(gzip压缩比较)快10-20倍,解析速度高一个数量级,
- 它可以表达更低级别的操作,这些操作无法适应JavaScript语法,例如asm.js(例如64位整数、特殊CPU指令、SIMD等)
- 可以(在某种程度上)转换为/from asm.js。
因此,目前WebAssembly是对asm.js的迭代,仅针对C/C++(和类似语言)。
Python在Web上的应用
我看起来似乎不是唯一阻止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,有几个现有项目:
PyPy: PyPy.js (author's talk at PyCon). Here's release repo. Main JS file, pypyjs.vm.js
, is 13 MB (2MB after gzip -6
) + Python stdlib + other stuff.
CPython: pyodide, EmPython, CPython-Emscripten, EmCPython, etc. empython.js
is 5.8 MB (2.1 MB after gzip -6
), no stdlib.
Micropython: this fork.
There was no built JS file there, so I was able to build it with trzeci/emscripten/
, a ready-made Emscripten toolchain. Something like:
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
It produces micropython.js
of 1.1 MB (225 KB after gzip -d
). The latter is already something to consider, if you need only very compliant implementation without stdlib.
To produce WebAssembly build you can change line 13 of the Makefile
to
CC = emcc -s RESERVED_FUNCTION_POINTERS=20 -s WASM=1
Then make -j
produces:
113 KB micropython.js
240 KB micropython.wasm
You can look at HTML output of emcc hello.c -s WASM=1 -o hello.html
, to see how to use these files.
This way you can also potentially build PyPy and CPython in WebAssembly to interpret your Python application in a compliant browser.
另一个可能有趣的东西是Nuitka,它是一个Python到C++的编译器。理论上,可以将Python应用程序构建为C++,然后使用Emscripten与CPython一起编译。但实际上我不知道如何操作。
解决方案
目前,如果您正在构建传统网站或Web应用程序,其中下载几兆字节的JS文件几乎不可行,请尝试Python到JavaScript的转换器(例如Transcrypt)或JavaScript Python实现(例如Brython)。或者尝试其他编译为JavaScript的语言列表。
否则,如果下载大小不是问题,并且您准备好处理许多棘手的问题,请在上述三种选择之间进行选择。
2020年第三季度更新
JavaScript port 被集成到MicroPython中。它位于ports/javascript。
该端口作为一个npm包MicroPython.js提供。您可以在RunKit中试用它。
有一个活跃的Python实现,使用Rust编写,叫做RustPython。由于Rust官方支持WebAssembly作为编译目标,因此毫不意外地,在自述文件的顶部就有演示链接。尽管如此,这还处于早期阶段。他们的免责声明如下:
RustPython 处于开发阶段,不应在生产环境或容错设置中使用。
我们当前的构建仅支持 Python 语法的子集。
2023年第一季度更新
Python 3.11在其文档中识别了两个WebAssembly“平台”,并在其中记录了其API的可用性,以及其他平台(如Linux和Unix)的详细信息(有关更多详细信息,请参见此PR)。它还推荐使用Pyodide(来自Mozilla)和另一个基于它的端口PyScript(来自Anaconda)。
The
WebAssembly 平台的
wasm32-emscripten
(
Emscripten) 和
wasm32-wasi
(
WASI)提供 POSIX API 的子集。 WebAssembly 运行时和浏览器都是沙盒化的,对主机和外部资源的访问受到限制。任何使用进程、线程、网络、信号或其他形式的进程间通信 (IPC) 的 Python 标准库模块都不可用或可能不能像其他类 Unix 系统上那样工作。
[...]
对于在浏览器中使用 Python,用户应该考虑使用 Pyodide 或 PyScript。 PyScript 建立在 Pyodide 之上,而 Pyodide 本身则建立在 CPython 和 Emscripten 之上。 Pyodide 提供了访问浏览器的 JavaScript 和 DOM API 的能力,以及通过 JavaScript 的 XMLHttpRequest 和 Fetch API 进行有限的网络功能。
pyodide
:https://hacks.mozilla.org/2019/04/pyodide-bringing-the-scientific-python-stack-to-the-browser - Alex