本文发自 http://www.binss.me/blog/try-webassembly/,转载请注明出处。
工作了,能用来折腾了时间少了。眼看书签列表越来越长,今天花时间处理了一下。处理过程中发现一种名为 WebAssembly 的技术,经过几年的发展已经逐渐成熟,主流浏览器也都提供了支持。初略了解了一下该技术,以文记之。
什么是 WebAssembly
做过 Web 开发的同学都知道,在 Web 的世界中,以 html 为骨架、css 为样式,而控制器则由 JavaScript 负责实现,比如用户按下一个按钮我们想弹个窗,那么我们就可以用 javascript 写个:
document.getElementById("btn").addEventListener("click", function() {
alert("hello");
}, false);
可以说一直以来,JavaScript 是我们和浏览器打交道、控制其行为的唯一通道。但 JavaScript 有很多为人诟病的地方,比如说性能差,性能差,还有性能差,JIT 也救不了那种。当然,还有语言本身无数的坑,写过的都躺过坑,ESxx 你今天学了吗。
于是各家都看不下去了,提出了自家的方案:
- Microsoft: 搞个强类型语言 TypeScript ,能够编译成 JavaScript ,提高代码健壮性
- Google: 搞个强类型语言 Dart ,能够编译成 JavaScript ,提高代码健壮性。也支持在原生虚拟机上执行
- Firefox :搞个 JavaScript 的子集 asm.js ,可通过标注加上类型,提高性能
有没有更好的办法来做这事呢?各大巨头们脑袋一拍,搞出一个 WebAssembly 。
个人理解, WebAssembly 不是一门编程语言,是一种新的字节码格式。该字节码和架构无关,但能够快速被翻译成相应架构的机器码,因此执行速度飞快。最骚的是其允许将高级语言,如 AssemblyScript、C/C++、Golang 等写成的程序编译成 WebAssembly 字节码,然后放到网页中加载执行了。哇,C/C++ 程序员也有能写 Web 的一天了,岂不美哉。
为什么 WebAssembly 会比 Javascript 快?
在浏览器上,一份代码从加载到执行,主要经历以下阶段:
- 获取:将代码下载下来。对于 JavaScript 来说,就是裸的代码。而对于 WebAssembly 来说,是编译好的字节码。即使经过压缩,JavaScript 往往还是比 WebAssembly 大
- 解析:JavaScript 代码下载下来后需要建立 AST,生成 IR。而 WebAssembly 早就生成好了
- 编译:JavaScript 需要编译。而 WebAssembly 早就由更高级的编译器(如 LLVM)料理好了,无需再进行类型推断和其他优化工作,只需进行简单的到目标架构的字节码转换
- 重优化:JavaScript 在 JIT 下特有的阶段:当上下文有变动、代码被多次执行时,JIT 决定重新编译这段代码,带来了额外的开销
- 运行:这部分的效率依赖于编译器的功力,一般来说 WebAssembly 生成的机器指令往往更优,运行效率更高
- 垃圾回收:JavaScript 的 GC 由浏览器来做,而 WebAssembly 需要开发者自己管理内存,所以无需进行 GC
综上所述,WebAssembly 比 Javascript 快。
实验
由于 WebAssembly 标准和工具链变化很快,网上很多文章都已经 out of date 了,比如 binaryen 已经移除了 s2wasm 。为此自己瞎折腾了一番。
首先我们需要一份 C/C++ 代码,主要参考自 https://github.com/richardanaya/llvm-8-wasm :
// main.c
// a simple way to export your functions
#define export __attribute__((visibility("default")))
// you would use this variable to write your own malloc/free
extern unsigned char __heap_base;
export void *get_heap_base() { return &__heap_base; }
export int add(int x, int y) { return x + y; }
主要需要将变量和函数暴露出去,才能在浏览器中调用。
随后用 LLVM 进行编译、链接:
clang main.c -S -emit-llvm --target=wasm32 -omain.ll
llvm-link -o main.bc main.ll
opt -O3 main.bc -o main.bc
llc -mtriple=wasm32-unknown-unknown -O3 -filetype=obj main.bc -o main.o
wasm-ld main.o -o main.wasm --no-entry --export-dynamic -allow-undefined
得到 WebAssembly 的 Binary :main.wasm 。
然后我们写个 html 加载它:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Hello WebAssembly</title>
<script>
if ('WebAssembly' in window) {
fetch('main.wasm')
.then(response => response.arrayBuffer())
.then(buffer => WebAssembly.compile(buffer))
.then(module => {
const instance = new WebAssembly.Instance(module);
console.log(instance.exports.__heap_base);
console.log(instance.exports.get_heap_base());
document.getElementById("btn").addEventListener("click", function() {
var lvalue = document.getElementById("lvalue").value;
var rvalue = document.getElementById("rvalue").value;
document.getElementById("result").setAttribute('value', instance.exports.add(lvalue, rvalue));
}, false);
});
} else {
output.value = "Your browser doesn't support Web Assembly. You may need to enable it in your browser's flags.";
}
</script>
</head>
<body>
<input type="text" id="lvalue" value="1"/> +
<input type="text" id="rvalue" value="2"/> =
<input type="text" id="result" disabled/>
<input type="button" id="btn" value="Run" />
</body>
</html>
然后用 python 起个 web server 加载之:
python -m SimpleHTTPServer 8000
可以发现 main.wasm 被加载,在 console 输出了内容:
然后我们点击 Run 按钮,调用我们 C 实现的 add 函数来实现加法:
More
WebAssembly.instantiate 函数支持以第二个参数传参给 callee ,比如传个 windows.alert 那么在 C 代码中就可以调用之来弹窗,然而网上没找到 C 版本的用法。
展望
JIT 的引入使 Web 进入了黄金发展期,得益于性能的提升,开发者们极大地丰富了网页的功能和样式。 WebAssembly 的诞生无疑又是一股春风。
以上的小 demo 能成功在 Mac OS Chrome 74 / Safari 12.1 上运行,同时也能在 IOS 12.3.1 的 Safari 上运行,说明主流浏览器都已经跟上了。事实上,目前已经有一些网站已经用上了 WebAssembly 。比如某些矿池实现的浏览器挖矿,实现上就是跑 WebAssembly 来挖,不得不说也是一种需要高性能的应用场景。
参考
https://github.com/richardanaya/llvm-8-wasm
https://www.ibm.com/developerworks/cn/web/wa-lo-webassembly-status-and-reality/index.html
https://hacks.mozilla.org/2017/02/what-makes-webassembly-fast/
1F tcbbd 5 years, 4 months ago 回复
我怀疑你在说熊神 nimiq 天池 挖矿
2F binss MOD 5 years, 4 months ago 回复
回复 [1F] tcbbd:这个 SEO 做的好啊 [举枪]