《徐林森《WebAssembly在腾讯文档表格的实践》.pdf》由会员分享,可在线阅读,更多相关《徐林森《WebAssembly在腾讯文档表格的实践》.pdf(78页珍藏版)》请在三个皮匠报告上搜索。
1、WebAssembly 在腾讯文档表格的实践徐林森腾讯前端工程师关于我徐林森(Aricxu)腾讯文档函数计算引擎负责人正致力于打造更快更好的 C+表格函数计算引擎也在进行前端业务 WebAssembly 化落地的探索与实践目录1.WebAssembly 技术概述2.基于 WebAssembly 的表格函数计算架构3.WebAssembly 落地经验分享4.WebAssembly 通用性能优化经验分享WebAssembly 技术概述Part.1Topic.WebAssembly 究竟是什么“WebAssembly(简称Wasm)是一种基于堆栈的虚拟机的二进制指令格式。”https:/webass
2、embly.org/计算 A+B 的 Wasm 代码(WebAssembly Text Format)Wasm 文本格式计算 A+B 的 Wasm 代码取出一个参数,入栈再取出个参数,入栈从栈上取出两个数,求和并将结果入栈(WebAssembly Text Format)Wasm 文本格式Wasm 指令是基于堆栈的wat2wasmWasm 代码是二进制的C+RustGolangWasm 二进制格式浏览器终端服务器EmscriptenGolang CompilerRust CompilerV8WasmtimeWasmer源语言运行时Wasm 能够支撑大型应用的构建吗?基于 Wasm 的大型应用案
3、例UI设计领域在线协同办公领域Photoshop Web图像编辑领域工业设计领域AutoCAD Web基于 Wasm 的大型应用案例UI设计领域在线协同办公领域Photoshop Web图像编辑领域工业设计领域AutoCAD Web基于 Wasm 的大型应用案例UI设计领域在线协同办公领域Photoshop Web图像编辑领域工业设计领域AutoCAD Web基于 Wasm 的大型应用案例UI设计领域在线协同办公领域Photoshop Web图像编辑领域工业设计领域AutoCAD Web哪些前端项目适合应用 Wasm 技术 存在现有 C+、Rust 代码库的项目;主要场景为 CPU 密集型计算
4、的项目;对代码安全性有严格要求的项目;C+、Rust 学习成本较高,前端开发想要尝试 Wasm,有没有上手成本更低的选择?AssemblyScriptA TypeScript-like language for WebAssembly.基于 WebAssembly 的表格函数计算架构Part.2Topic.由来以及架构的演进既然已经有 JS 函数计算引擎了,为什么要有 Wasm 函数计算引擎?为什么要有 Wasm 函数计算引擎原因1 旧版本的函数计算引擎的性能不足以支撑更大规模的计算5000.ms210.ms旧版计算引擎旧版计算引擎新版计算引擎新版计算引擎*一百万个公式规模下新旧计算引擎的计算
5、耗时对比20 x faster!为什么要有 Wasm 函数计算引擎原因2 JS 逻辑逆向成本较低,难以保护核心算法资产执行流程混淆变量名混淆函数名混淆*如图是一份经过良好混淆的 JS 代码为什么要有 Wasm 函数计算引擎原因3 后台与 Native 客户端急需函数计算能力,现在只有 JS 版,若嵌入 V8 复用 JS 代码成本过高函数计算引擎后台服务Go客户端Flutter(Dart)函数后台(函数结果直出)函数计算(函数本地计算)为什么要有 Wasm 函数计算引擎原因1 旧版本的函数计算引擎的性能不足以支撑更大规模的计算原因2 JS 逻辑逆向成本较低,难以保护核心算法资产原因3 后台与 N
6、ative 客户端急需函数计算能力,若嵌入 V8 复用 JS 代码成本过高用 C+重写函数计算引擎.so(shared object)Native 客户端Flutter(Dart)C+函数计算引擎.so(shared object)后台服务GoC+函数计算引擎后台服务Go前端JS客户端Flutter(Dart)独立维护 JS 和 C+的函数计算引擎成本太高前端如何复用C+函数计算引擎?.so(shared library).so(shared library)前端如何复用 C+函数计算引擎?C+函数计算引擎后台服务Go前端JS客户端Flutter(Dart).so(shared library
7、).so(shared library)asm.jsWasmC+EmscriptenEmscripten前端如何复用 C+函数计算引擎?C+函数计算引擎后台服务Go前端JS客户端Flutter(Dart).so(shared library).so(shared library)asm.jsWasmC+asm.jsWasm代码尺寸较大(文本)较小(二进制)编译器支持度较低优先级优先支持安全性与普通 JS 拥有相同权限沙箱执行性能表现与普通 JS 基本一致在 CPU 密集型场景下优于 JS浏览器兼容性所有浏览器都支持少部分浏览器不支持EmscriptenEmscripten最终决定以 Wasm
8、的方式复用 C+函数计算引擎,asm.js 作为 Wasm 不支持时的备选方案.so(shared object)C+函数计算引擎.so(shared object)后台服务Go前端JS客户端Flutter(Dart).wasm一份代码,三端同构腾讯文档三端同构的首次实践C+函数计算引擎后台服务Go前端JS客户端Flutter(Dart)一份代码,三端同构如何在前端应用 Wasm 函数计算引擎?.so(shared object).so(shared object).wasm腾讯文档三端同构的首次实践主线程Worker 线程函数引擎主线程适配层JS 函数计算引擎表格数据层函数解析器函数依赖图公
9、式计算器用户操作(Mutation)计算结果(Mutation)postMessagepostMessageJS 版本的函数计算架构JS 方案Worker 线程Wasm 方案一JS 数据层子表属性单元格值单元格样式Wasm 函数计算引擎函数解析器函数依赖图公式计算器Worker 线程JS 数据层作为数据源JS 函数计算引擎表格数据层函数解析器函数依赖图公式计算器JS 方案Worker 线程Wasm 方案一JS 数据层子表属性单元格值单元格样式Wasm 函数计算引擎函数解析器函数依赖图公式计算器Worker 线程JS 函数计算引擎表格数据层函数解析器函数依赖图公式计算器计算 SUM(A1:A10
10、0)请求A1数据A1数据请求A2 数据A2数据*98 次JS 方案Worker 线程Wasm 方案一JS 数据层子表属性单元格值单元格样式Wasm 函数计算引擎函数解析器函数依赖图公式计算器Worker 线程JS 函数计算引擎表格数据层函数解析器函数依赖图公式计算器计算 SUM(A1:A100)JS 胶水频繁经过 JS 胶水会使性能下降Wasm 方案一Wasm 函数计算引擎函数解析器函数依赖图公式计算器Worker 线程计算 SUM(A1:A100)JS 数据层子表属性单元格值单元格样式JS 胶水Wasm 函数计算引擎Worker 线程表格数据层函数解析器函数依赖图公式计算器计算 SUM(A1
11、:A100)Wasm 方案二请求A1数据A1数据请求A2 数据A2数据*98 次数据源在 JS 层数据源在 Wasm 内尽量减少经过 JS 胶水主线程Worker 线程函数引擎主线程适配层JS 胶水Wasm 函数引擎表格数据层函数解析器函数依赖图公式计算器用户操作(Mutation)用户操作(TypedArray)计算结果(Mutation)计算结果(TypedArray)postMessagepostMessageJS 只充当数据转发与类型转换职责,逻辑尽量轻量化避免频繁经过 JS 胶水。应用 Wasm 的成本如何 C+、Rust 等语言的学习成本如何?C+的开发效率相较于 JS 如何?使用
12、 Emscripten 将 C+代码编译为 Wasm 的成本有多高?C+代码 Wasm 化后前端 JS 层接入的成本如何?应用 Wasm 的成本如何 C+、Rust 等语言的学习成本如何?C+的开发效率相较于 JS 如何?使用 Emscripten 将 C+代码编译为 Wasm 的成本有多高?C+代码 Wasm 化后前端 JS 层接入的成本如何?边学边写,一周左右能有产出。但是前期的代码需要有熟悉 C+的同学负责 CR 以避免跑偏 C+、Rust 等语言的学习成本如何?C+的开发效率相较于 JS 如何?使用 Emscripten 将 C+代码编译为 Wasm 的成本有多高?C+代码 Wasm
13、化后前端 JS 层接入的成本如何?应用 Wasm 的成本如何在熟悉 C+后,实现相同的需求,其人力花费大概为 JS 的 1.5 倍,但代码健壮性通常更佳边学边写,一周左右能有产出。但是前期的代码需要有熟悉 C+的同学负责 CR 以避免跑偏 C+、Rust 等语言的学习成本如何?C+的开发效率相较于 JS 如何?使用 Emscripten 将 C+代码编译为 Wasm 的成本有多高?C+代码 Wasm 化后前端 JS 层接入的成本如何?应用 Wasm 的成本如何在熟悉 C+后,实现相同的需求,其人力花费大概为 JS 的 1.5 倍,但代码健壮性通常更佳绝大多数 C+代码都能够毫不费力的编译为 W
14、asm,但是 Emscripten 的编译选项较为灵活,需要根据项目情况灵活调整边学边写,一周左右能有产出。但是前期的代码需要有熟悉 C+的同学负责 CR 以避免跑偏 C+、Rust 等语言的学习成本如何?C+的开发效率相较于 JS 如何?使用 Emscripten 将 C+代码编译为 Wasm 的成本有多高?C+代码 Wasm 化后前端 JS 层接入的成本如何?应用 Wasm 的成本如何在熟悉 C+后,实现相同的需求,其人力花费大概为 JS 的 1.5 倍,但代码健壮性通常更佳在 Wasm 架构设计合理的情况下,JS 接入层的逻辑都是较为轻量的,接入成本是很低的绝大多数 C+代码都能够毫不费
15、力的编译为 Wasm,但是 Emscripten 的编译选项较为灵活,需要根据项目情况灵活调整边学边写,一周左右能有产出。但是前期的代码需要有熟悉 C+的同学负责 CR 以避免跑偏WebAssembly落地经验分享Part.3Topic.为了在前端落地 Wasm 需要做的Wasm 兼容性问题处理Wasm 的浏览器兼容性如何?兼容性似乎不错?数据于 2023/11/04 更新 https:/ 2023/11/04 更新其实 Can I use 只是简单的统计了 Wasm1.0 的浏览器兼容性数据但在实际的应用过程中,我们通常会使用超出 Wasm1.0 标准的一些额外特性 https:/webas
16、sembly.org/roadmap/https:/webassembly.org/roadmap/不支持15%支持85%Threads and atomics 的支持情况 https:/webassembly.org/roadmap/不支持15%支持85%Threads and atomics 的支持情况有必要设计 Wasm 降级策略加载 asm.js成功加载 Wasm加载 asm.js否是否否是是Wasm 降级策略Wasm 特性检查Wasm 基础能力检查Wasm 编译检查下载完整 Wasm下载剔除特性的 Wasm是否支持 Wasm是否支持Threads 特性是否正常编译asm.js是 Ja
17、vaScript 的严格子集,若浏览器对 asm.js 有优化处理,可以达到接近 Wasm 的稳定性wat2wasm特性检查的实现包含 Threads 特性的最小代码片段构建剔除指定特性的降级包Wasm 断点调试与异常堆栈上报Wasm 指令格式可读性差,基本无法直接断点调试Wasm 源码级调试Wasm 指令格式可读性差,基本无法直接断点调试可以通过 DWARF 将堆栈映射回 C+源码Wasm 源码级调试Wasm 异常堆栈上报函数名丢失Wasm 异常堆栈上报函数名丢失保留了函数名WebAssembly通用性能优化经验分享Part.4Topic.从 Wasm 函数计算引擎实践中提炼出的通用优化经验
18、如何在浏览器中充分发挥 Wasm 的性能?ChromeV8 EngineDOM APIFetch APICanvas API浏览器中的 WasmnumbersnumbersCallCallJS 与 Wasm 互调发生了什么JSWasmJSJS 调用 Wasm 函数:sum(1,2)传递参数返回结果C+中间层JSWasmC+中间层JSJS 调用 Wasm 函数:sum(1,2)数据转换与拷贝(存在上下文切换成本)数据转换与拷贝(存在上下文切换成本)测试一下 Wasm 与 JS 互调的耗时300 ms2,725 ms5,150 ms7,575 ms10,000 ms0 KB1KB2 KB3 KB4
19、 KB5 KB作为参数的 ArrayBuffer 的尺寸JS 调用调用100万次万次Wasm 耗时耗时0 KB 时 300 ms(仅上下文切换开销)JS 与 Wasm 互相调用的特点:1.每一次调用都存在上下文切换开销,且无法避免2.调用的整体耗时随传递的参数尺寸线性增长300 ms2,725 ms5,150 ms7,575 ms10,000 ms0 KB1KB2 KB3 KB4 KB5 KB作为参数的 ArrayBuffer 的尺寸JS 调用调用100万次万次Wasm 耗时耗时0 KB 时 300 ms(仅上下文切换开销)JS 与 Wasm 互相调用的特点:1.每一次调用都存在上下文切换开销
20、,且无法避免2.调用的整体耗时随传递的参数尺寸线性增长Wasm 性能优化原则:减少 JS 与 Wasm 互调次数,一次传递大量数据要优于多次传递少量数据如何让 Wasm 在浏览器发挥出它本该有的峰值性能?下面有一个 Wasm 性能优化的实际案例AVERAGE(B3:C4)COUNT(B3:C4)SUM(B3:C4)选区数据分析功能例子可以改成 NumberFormatterAVERAGE(B3:C4)COUNT(B3:C4)SUM(B3:C4)AVERAGE(B3:C4)计算 AVERAGE请求计算 B3:C4 的平均值缺少 B3 单元格数据获取 B3 单元格并返回请求获取 B3 单元格数据缺
21、少 B4 单元格数据获取 B4 单元格并返回请求获取 B4 单元格数据该功能是在主线程执行的,主线程没有 Wasm 数据层,有别于之前 Worker Wasm 函数计算引擎架构AVERAGE(B3:C4)COUNT(B3:C4)SUM(B3:C4)AVERAGE(B3:C4)计算 AVERAGE请求计算 B3:C4 的平均值缺少 B3 单元格数据获取 B3 单元格并返回请求获取 B3 单元格数据缺少 B4 单元格数据获取 B4 单元格并返回请求获取 B4 单元格数据想要完成一次 AVERAGE 计算,JS 与 Wasm 间需要互调多次AVERAGE(B3:C4)计算 AVERAGE请求计算 B
22、3:C4 的平均值缺少 B3 单元格数据获取 B3 单元格并返回请求获取 B3 单元格数据缺少 B4 单元格数据获取 B4 单元格并返回请求获取 B4 单元格数据当单元格规模较大时,JS 与 Wasm 互调的成本将是不可忽略的请求获取AVERAGE(B3:C4)计算 AVERAGE(B3:C4)Wasm 沙箱B3 单元格B4 单元格C3 单元格C4 单元格单元格缓存从缓存获取 B3 单元格从缓存获取 B4 单元格计算出平均值接收计算结果Wasm 性能优化原则:减少 JS 与 Wasm 互调次数,一次传递大量数据要优于多次传递少量数据请求计算 B3:C4 平均值缺少 B3:C4 数据获取 B3:
23、C4 数据一次性将 B3:C4 数据传递给 Wasm优化前:N 次互调 优化后:1 次互调20.ms110.ms410.ms722.ms1210.ms16.ms65.ms197.ms330.ms590.ms1万10万50万100万150万优化前后计算耗时对比总结与展望当下的 WebAssembly 代码库的高效复用,是多端同构的利器 性能足够强大,足以支撑大型商业项目的开发 社区生态较为活跃,不断有新的 WebAssembly 特性提案被提出What are you using WebAssembly for at the moment?未来的 WebAssembly 不局限于 WebWasm 容器相对于传统容器的优点:镜像体积更小 容器启动速度更快 沙箱隔离更彻底谢 谢 观 看THANKS