Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
社区首页 >专栏 >为什么有的语言「不能」编译成 WASM?

为什么有的语言「不能」编译成 WASM?

作者头像
tyrchen
发布于 2020-04-15 09:03:38
发布于 2020-04-15 09:03:38
7.4K3
举报
文章被收录于专栏:程序人生程序人生

在上一篇文章「dart:失之东隅收之桑榆」里,我写了这样一句:

dart 也许未来可以支持 WebAssembly(类似 golang,有没有意义再说);而 TypeScript 没有这种可能。

于是很多 TypeScript 的拥趸不开心了,为什么说我家宝宝不能支持 WebAssembly(下文称 WASM)?有人找出了证据:看,AssemblyScript[1] 明明就可以支持 TypScript 转换成 WebAssemby 嘛。我不知道说这话的人是否真的看过 AssemblyScript,还是道听途说,仅仅知道有这个么东西,就像北京的的哥那样,说着让人不明觉厉的话。其实只要去 AssemblyScript 的 repo 看一眼,hub clone assemblyscript/assemblyscript,随便运行一下里面的例子,你就会发现:

不好意思,走错片场了:

为什么?为什么明明是 TypeScript 代码用 tsc 编译不过?如果你去它的官网 assemblyscript.org 瞅一眼文档,就该明白它们的基础数据类型就有很大的不同 —— 对于数字类型,TypeScript 沿袭了 javascript 的 number,而 AssemblyScript 使用了 i8,u16,f64 等 WASM 的类型。所以我这么回复:

AssemblyScript 明确说明自己 Definitely not a TypeScript to WebAssembly compiler. 你无法把已有的 TypeScript 直接转换成 WASM. TypeScript 沿用了 javascript 的 internal types(因为最终会编译成 javascript),而 WASM 有 u8, u16, isize 这样的类型。AseemblyScript 只是语法层面基本和 TypeScript 保持一致而已。你在写 TypeScript 的时候需要非常小心,避免使用整个 TypeScript/javascript 的生态圈。还要小心语法上的一些不同,比如 ===,null的检查等。

其实 AssemblyScript 只是一个包装着 TypeScript 语法的新语言而已。那么,为什么 TypeScript 自己直接不能被翻译成 WASM 呢?既然我们为这个话题展开了讨论,我们不妨简单了解一下 WASM,然后问一个更通用的问题:怎么判断某种语言能不能,或者值不值得转换成 WASM 呢?

什么是 WASM?它解决什么问题?

WASM 的官网 webassembly.org 是这样定义的[2]:

WebAssembly (abbreviated Wasm) is a binary instruction format for a stack-based virtual machine. Wasm is designed as a portable target for compilation of high-level languages like C/C++/Rust, enabling deployment on the web for client and server applications.

首先 WASM 是一组指令集格式,这组指令集可以运行在一个特定的基于栈的 VM 上。VM 一般有基于寄存器(erlang)的和基于栈(java)的,WASM 选择了后者,很大一个原因是为了产生更小的程序代码。WASM 的前身是 asm.js,当时 Mozilla 的工程师尝试着把大型的 C/C++ 项目编译成 javascript 的一个隐含类型的,为 JIT 编译器高度优化的子集,结果得到了在浏览器里近乎接近原生应用的效率。之后,Mozilla,Google,Microsoft,Apple 四巨头坐在一起,共同定义和开发了 WASM 技术,并在各自的浏览器中进行支持。2019 年 12 月,WASM 正式被接纳为 W3C 推荐标准[3][4],成为浏览器中除了 HTML/Javascript/CSS 之后,第四个原生的可执行语言。

WASM 在设计之初就和 javascript 是并行的语言,它的出现不是为了取代 javascript,相反,javascript 还为 WASM 代码的执行起粘合作用。WASM 的强项在于可以将 javascript 生态圈之外的已有代码,尤其是 C/C++,搬运到 web 上,这样能够大大丰富 web 的生态圈,使得原本难以用 javascript 重写的很多系统可以被放在 web 上,比如 vim[5]。

WASM 最早的实现是 Enscripten 编译器,它使用 LLVM,把 C/C++ 代码编译成 WASM,理论上来说,任何使用 LLVM 的编译器都可以使用其支持 WASM。早期的 Rust 通过 Enscripten 支持 WAS,后来提供了自己的 wasm32-unknown-unknown 更好地支持 WASM。Enscripten 除了可以把 C/C++ 代码编译成 WASM 外,它还模拟了 Unix 的运行环境,这让很多的 C/C++ 代码可以做进行少量修改(主要是编译脚本)就可以编译成 WASM。然而,一旦你使用了多线程(WASM 目前还不支持),或者特殊的设备驱动,或者阻塞操作(如 block wait),那么代码需要做不少修改。此外,传统的桌面和命令行软件,其和用户交互的部分也需要修改。下图是 vim.wasm 对 Vim 的交互做的改动:

其整个编译过程如下:

尽管 WASM 已经发展了有五年之多,目前,对 WASM 真正具备完整的,有意义的支持的语言也就是 C/C++/Rust。其它语言的支持要么是残缺的,要么是不可用的。

我们拿 golang 为例。一个基本的 hello world 编译成 WASM 要 2M 多(估计主要是因为 golang 运行时的代码):

虽然我们可以用很多 hack 把编译结果弄到 1M 多,但这个结果对 web 来说是不可接受的。此外,golang 还没有完全兼容 WASM 1.0 协议,所以不算可用[7]。TinyGo 对 WASM 的支持看上去很有前途,但仅仅因为 TinyGo 不支持 reflection,就自动过滤了 golang 生态圈一大票依赖,比如 protobuf。很多时候,语言的生态本身要比其语法重要得多。语法不难复刻,但生态是需要很长的时间成长起来的。

好在 WASM 目前在飞速发展,有很多功能在讨论和实现之中。比如说:GC 的支持和多线程的支持。有了这两个利器,尤其是 GC 的支持,可以让很多依赖 GC 的语言产生更小的字节码(golang 喜极而泣),这样,WASM 将来可以被更多的语言支持。

有同学拿 awesome-wasm-langs[8] 来反驳我,说:不止 C/C++/Rust,现在已经有几十种语言支持 WASM 了,比如 Python。这个列表的确唬人,但仔细看,比如 pyodide,明明是 python 及其科学计算相关的库被编译成了 WASM 啊?这其实是把用来写 python 解释器的 C 代码编译成 WASM,然后可以执行 Python 代码而已,并不是把 Python 代码编译成 WASM —— 当然如果你非要较真这 TM 就是 Python 支持 WASM 我也无话可说。pyodide 解压下来有 300M,其 WASM 主体也有 13M。这显然不是给正常的 web 使用场景准备的。

我无意贬低 pyodide,这是一个很好的在线运行数据科学家工具集的好工具,就像 unreal 引擎运行在浏览器一样,对特定需求的受众有很强大的吸引力(所以它们不介意加载速度)。但它并不意味着你写一段 hello world,可以通过 pyodide 得到一个能够单独加载的 WASM,这是两回事。如果一门语言对 WASM 的支持是这样子支持,那么的确,在下输了,所有语言都马上能「支持」WASM。

为什么 TypeScript 不太可能支持编译成 WASM?

我们回到本文开头的探讨。我很喜欢 TypeScript,它是一门设计得很精妙的语言。但我觉得 TypeScript 不太可能支持编译成 WASM。两个原因:

首先,二者的类型系统有一些鸿沟(前文已经提到了),如果强要把 TypeScript 编译成 WASM,需要 AssemblyScript 这样的语言。然而,这样就意味着整个 TypeScript 和 javascript 的生态圈就很可能无法使用了。而 TypeScript 最大也是最成功的优势就是在为项目渐进式地引入类型系统的同时,保持了对整个生态圈的兼容。如果这个优势不存在,那么使用它的意义何在?

其次,为什么我们要把 TypeScript 编译成 WASM?它能带来什么好处?

更好的性能?如果项目对性能的需求真的变态高,高到是 TypeScript 解决不了的,比如构建一个游戏引擎,那为何不换一种效率更高的语言,比如 rust 撰写,然后编译成 WASM 呢?

更小的代码体积?抱歉,这个 WASM 真的要吼:臣妾做不到啊。

更高效地和 DOM 以及浏览器事件互操作?抱歉,WASM 操作 DOM 需要经过 javascript。。。再看看上图 vim.wasm 是怎么做的。

。。。

如果我们无法回答这个问题,那么花那么大精力支持把 TypeScript 编译成 WASM 有什么意义?仅仅是为了赶时髦搭上新技术的列车么?

我们看 chrome 里对 javascript 和 WASM 的支持:

可以看到,二者是不是取代,而是并存的关系。它们背后使用了同样的执行引擎 TurboFan。javascript 代码在解析和 JIT 阶段会耗费不少时间,但一旦代码在运行时被优化后,其执行效率和 WASM 并没有太大的区别。而对 javascript 这样灵活的语言来说,运行时的优化比 AOT 时期的优化能够做更多的事情。如果强行把它在编译期编译好,反而可能影响运行时的效率。所以,我想不太出来把 TypeScript 编译成 WASM 的在 web 上的使用场景。

当然,WASM 还有一个不容忽视的使用场景是服务器端。它脱胎于 web 的安全性使得它成为后端取代 docker 这样的沙箱的绝好平台。如果 WASI 相关的应用在后端蓬勃发展,那么对于一个 TypeScript 工程师,可以写能够运行在服务器端的 WASM 运行时 wasmer / wasmtime 上,也许还是有些吸引力的。这也许是唯一的,把 TypeScript 编译成 WASM 的理由。

参考文献

  1. AssemblyScript:https://docs.assemblyscript.org/
  2. WebAssembly 官方文档:https://webassembly.org
  3. WebAssembly Wikipedia:https://en.wikipedia.org/wiki/WebAssembly
  4. WebAssembly Core Specification: https://www.w3.org/TR/wasm-core-1/
  5. Vim WASM: https://rhysd.github.io/vim.wasm/
  6. Enscripten: https://emscripten.org/
  7. Golang: Are we WebAssembly Yet?: https://medium.com/@KevinHoffman/golang-are-we-webassembly-yet-e0a2e180fc98
  8. Awesome WASM langs: https://github.com/appcypher/awesome-wasm-langs
  9. WebAssembly for Web Developers: https://www.youtube.com/watch?v=njt-Qzw0mVY
  10. AssemblyScript is not a subset of TypeScript: https://dev.to/jtenner/AssemblyScript-is-not-a-subset-of-TypeScript-4ka3
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-04-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序人生 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
3 条评论
热度
最新
写得非常好,特意登录点赞
写得非常好,特意登录点赞
回复回复点赞举报
写的很好,但作者忽略了一个重要问题:WASM就一定要运行在浏览器中吗?
写的很好,但作者忽略了一个重要问题:WASM就一定要运行在浏览器中吗?
回复回复点赞举报
为什么希望typescript编译成wasm?因为我只会typescript
为什么希望typescript编译成wasm?因为我只会typescript
回复回复点赞举报
推荐阅读
编辑精选文章
换一批
Wasm 为 Web 开发带来无限可能
大家好,我是 ConardLi,不知道有没有小伙伴关注今年的 Google 开发者大会,今年的大会在 11.16 号开始。
ConardLi
2021/11/24
1.8K0
Wasm 为 Web 开发带来无限可能
Go每日一库之132:wasm与tinygo
WASM 的概念,这几年还是挺火的,新的语言,比如 Rust、Go、Swift 等,都对 WASM 提供支持。相比之下,Go 语言的简单性,使得对 WASM 的支持,使用起来也较简单。本文是目前公开资料中为数不多较完整的教程,希望能对你有帮助。
luckpunk
2023/09/30
2.6K0
WebAssembly 技术汇总
Mozilla 开发的在线IDE,支持Rust、C、Wat开发WebAssembly
我不是码神
2022/07/28
1.1K0
CloudBluePrint-Chapter 1.8 : 云上应用技术架构-WebAssembly (WASM)
从物理机,到虚拟机,再到容器引擎,最后到WebAssembly,计算领域的技术趋势主要包括以下几个方面:
行者深蓝
2023/09/07
5470
为什么说 WASM 是 Web 的未来?
了解 WebAssembly 的前世今生,这一致力于让 Web 更广泛使用的伟大创造是如何在整个 Web/Node.js 的生命周期起作用的,探讨为什么 WASM 是 Web 的未来?
玖柒的小窝
2021/12/03
1.2K0
为什么说 WASM 是 Web 的未来?
AssemblyScript 入门指南[每日前端夜话0xEB]
WebAssembly【https://webassembly.org/】(Wasm)是 Web 浏览器中相对较新的功能,但它地扩展了把 Web 作为服务应用平台的功能潜力。
疯狂的技术宅
2019/11/25
1.2K0
AssemblyScript 入门指南[每日前端夜话0xEB]
WASM·技术趋势
今天看到一则故事,一名程序员@Andreas Kling 辞掉工作,全职开发操作系统。正如其签名档一样:I like computers! 对技术的热爱已经超越了工作本身,完全是兴趣所在
mixlab
2021/10/12
1.7K0
WebAssembly完全入门——了解wasm的前世今身
接触WebAssembly之后,在google上看了很多资料。感觉对WebAssembly的使用、介绍、意义都说的比较模糊和笼统。感觉看了之后收获没有达到预期,要么是文章中的例子自己去实操不能成功,要么就是不知所云、一脸蒙蔽。本着业务催生技术的态度,这边文章就诞生了。前部分主要是对WebAssembly的背景做一些介绍,WebAssembly是怎么出现的,优势在哪儿。如果想直接开始撸代码试试效果,可以直接跳到最后一个板块。
SH的全栈笔记
2019/10/21
1.8K0
WebAssembly完全入门——了解wasm的前世今身
为什么WebAssembly不是JavaScript的终结者,而是它的“助推器”?
导语 | 自从JavaScript创建到现在,每10年都会有新的变化,下一个10年的爆点在哪,可能就是WebAssembly!但WebAssembly绝不是JavaScript的终结者,反而是它的“助推器”!这是为什么呢?接下来我将带你揭晓答案,让你10分钟快速掌握WebAssembly! 一、了解WebAssembly (一)什么是WebAssembly? 官网定义:WebAssembly/wasm WebAssembly或者wasm是一个可移植、体积小、加载快并且兼容Web的全新格式(二进制),
腾讯云开发者
2021/09/18
1.1K0
WASM能否取代Docker?
云计算、微服务计算、无服务器计算、可扩展计算、可负担计算等等,这一切主要靠一项杰出的技术——Linux容器(LXC)来实现。
溪歪歪
2020/11/24
2K0
WASM能否取代Docker?
使用 Docker 和 Golang 快速上手 WebAssembly
本文将聊聊,如何使用 Docker 和 Golang 快速上手 WebAssembly。我会分别从浏览器场景和“通用应用”场景来进行叙述,如果你还徘徊在 WebAssembly 的门前,或许这篇文章会对你所有帮助。
soulteary
2021/11/25
1.2K0
使用 Docker 和 Golang 快速上手 WebAssembly
WebAssembly 与 Rust 综述
首先要说一句,WebAssembly 是一项极速发展的技术,互联网上流传的很多文章(17,18年所写)已经过时了。所以,请尽量查阅最新时间的相关描述文档。
MikeLoveRust
2019/07/09
1.8K0
WebAssembly 与 Rust 综述
WASM 将引领下一代计算范式!
WebAssembly 是一种新兴的网页虚拟机标准,它的设计目标包括:高可移植性、高安全性、高效率(包括载入效率和运行效率)、尽可能小的程序体积。2018 年 WebAssembly 第一个规范草案诞生,2019 年成为 W3C 第四个标准语言。到了 2022 年底,WebAssembly 现在怎么样了 ...
米开朗基杨
2022/11/07
1.3K0
WASM 将引领下一代计算范式!
一文带你走进 Rust 和 WebAssembly 的世界
在进行正式的分享之前,先来说一说为什么,要学习 Rust 这一门在广义上归属于后端的语言,以及它能带给我们什么,未来有什么前景。
童欧巴
2021/08/20
2.2K0
一文带你走进 Rust 和 WebAssembly 的世界
Shopify 如何在浏览器之外使用 WebAssembly?
Shopify 致力于让大多数商家都需要的功能变得简单易用,并通过接口在 Shopify 平台上执行查询、扩展和更改,进而为商家提供更多可能。借助这些接口,我们丰富的合作伙伴生态系统可以解决诸多问题。这一生态系统主要借助“App”(一个独立托管的 Web 服务)来运作。该 App 通过网络与 Shopify 进行通信。尽管这种模式很强大,但会带来一系列技术问题。我们的合作伙伴需要打造能够随 Shopify 规模扩展的 Web 服务,这让一些本就资源有限的合作伙伴越发捉襟见肘。即便合作伙伴有无限的资源,在与 Shopify 通信时产生的网络延迟也足以让我们的 App 在对时效性要求很高的用例中败下阵来。
深度学习与Python
2021/01/20
9570
Rust 是 JavaScript 基础设施的未来
Rust[2] 是一种快速、可靠、内存高效的编程语言。它已经连续六年被评为最受 欢[3] 迎[4] 的 编[5] 程[6] 语[7] 言[8] 。它由 Mozilla 创建,现在被 Facebook[9] 、 苹果[10] 、 亚马逊[11] 、 微软[12] 和 谷歌[13] 用于系统基础设施、加密、虚拟化和更多底层(low-level)的编程中。
桃翁
2021/11/19
1K0
Rust 是 JavaScript 基础设施的未来
快 11K Star 的 WebAssembly,你应该这样学
长期以来,VM 只能加载 JS 运行,JS 可能足够满足我们的需求,但如今我们却遇到了各种性能问题,如 3D 游戏、VR/AR、计算机视觉、图片/视频编辑、以及其他需要原生性能的领域。
玖柒的小窝
2021/09/29
3K0
快 11K Star 的 WebAssembly,你应该这样学
尝试用 Rust + Yew 写高性能前端页面
看到这篇文章,可能很多人会有个疑问:“已经有 React + TypeScript 这么好的组合,为什么还想着使用 Rust 来写前端页面,不折腾吗?”
winty
2021/05/18
2.6K0
尝试用 Rust + Yew 写高性能前端页面
Rust 会成为 JavaScript 基础设施的未来吗?
Rust 最初由 Mozilla 创建,是一种快速、可靠、内存效率高且非常流行的编程语言,专为提高性能和安全性而设计。它连续 6 年被 Stack Overflow 调查评为最喜爱的编程语言,并在超大规模的公司使用,如 Facebook,苹果,亚马逊,微软和谷歌等用于系统基础设施、加密和虚拟化。Rust 现在正在取代 JavaScript Web 生态系统的部分内容,例如压缩 (Terser)、转译 (Babel)、格式化 (Prettier)、打包 (webpack)、linting (ESLint) 等等。让我们深入探讨一下为什么这种趋势越来越受欢迎和被广泛采用。
MikeLoveRust
2022/03/27
1.4K0
Go WebAssembly 入门(一)
有关WebAssembly的介绍可以参考 几张图让你看懂WebAssembly 简单来说WebAssembly就是将其他语言C/Go/Rust等语言编译成wasm可执行二进制文件,浏览器来执行wasm。wasm相比JS,拥有体积更小,执行更快,因为最终编译成二进制文件,所以一些安全策略代码也更适合wasm。 经过尝试C和Go分别编写WebAssembly,相较而言我认为Go无论从语言层面还是工具链,用起来都更加方便一些。 本文使用原生go build,生成的wasm文件大约在1.4M左右,在生产环境中这个体积是很大的,优化go的wasm体积可以使用tinygo来build,同样的代码使用tinygo构建之后约为22K,甚至比C语言构建wasm的体积还要小(C语言 build后约为44K,不同版本不同环境可能略有差异)。参考https://tinygo.org/
luckpunk
2023/09/10
5550
推荐阅读
相关推荐
Wasm 为 Web 开发带来无限可能
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 腾讯技术创作特训营