使用 rust+webassembly 进行 Web 开发,如何解决 wasm 和 js 交互的额外成本



我目前正在尝试使用 Rust 编译成 wasm 部分开发 Web 应用程序的一部分(有类似的框架,如 yew 等(,但我发现使用 webassembly 可能会有更多的消耗,例如,我必须做一个点击按钮调用 JS 函数。JS函数执行一些计算(非常简单的计算(并将结果呈现给dom

仅使用 js 的解决方案:

JS
  • 调用另一个JS函数
  • 另一个 JS 函数执行一些计算,并通过文档的一些 API 直接呈现结果。

使用 Rust + Webassembly 的解决方案:

  • JS调用wasm函数
  • Wasm执行一些计算。计算完成后,结果被编码到TypedArray中,并调用JS函数来呈现dom。
  • JS解码TypeArray中的相应内容,然后将dom渲染到屏幕。

这里我们不考虑使用 React 或者 Vue,单纯使用 WebAssembly 可能会降低性能,这主要体现在:

  • 更多函数调用
  • 添加了编码/解码过程和可能的内存副本。

Webassembly 的优点可能是计算速度更快,但是由于上面提到的开销增加,这个优点很可能不会节省整体时间,而且在 DOM 操作方面显然很慢。

但我仍然对 DOM 操作进行了比较测试:

JS创建10,000个p标签,大约需要120ms:

function web_bench() {
let container = document.getElementById("container");
let begin = Date.now();
for(let i = 0; i < 10000; i += 1) {
let str = "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" +
"123456789012345678901234567890123456abcd123456789012345678901234567890123456789012345678901234567890" +
"1234567890123456789012345678901234567890123456789012345678哈哈1234567890123456789012345678901234567890" +
"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" +
"1234567890123456789012345678901234567890123456789哈哈2345678901234567890123456789012345678901234567890" +
"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" +
"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" +
"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" +
"123456789012345678901234567890123456789012345678901234567890123嘻嘻67890123456789012345678901234567890" +
"12345678901234567890123456789012345678901234哈哈哈012345678901234567890123456789012345678901234567890";
let p = document.createElement("p");
p.innerHTML = str;
container.appendChild(p);
}
let time = Date.now() - begin;
console.log('cost time:', time);
}

如果我使用 rust:成本 180ms

#[wasm_bindgen]
pub fn bench() {
let document = web_sys::window().unwrap().document().unwrap();
for i in 0..10000 {
let str = "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456abcd1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678哈哈123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789哈哈234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678902345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123嘻嘻6789012345678901234567890123456789012345678901234567890123456789012345678901234哈哈哈012345678901234567890123456789012345678901234567890";
let p = document
.create_element("p")
.unwrap();
p.set_inner_html(str);
document
.get_element_by_id("container")
.unwrap()
.append_child(&p);
}
}

这是否意味着 rust+wasm 不适合与 dom 操作交互频繁的 Web 开发,只适用于计算模块。当前的 Rust Web 框架如何看待这个问题?我的分析正确吗?

谢谢你的意见~

有一些事情会增加 JS <=> WebAssembly 调用的开销,并影响性能:

  1. 在 WebAssembly 和 JavaScript 之间进行通信涉及相当多的开销,涉及通过C++代码称为蹦床的过程。
  2. 为了交换数据(简单数字除外(,需要通过线性存储器对值进行编码/解码。

这两者都有助于在每个函数调用的基础上产生可衡量的开销。

但是,情况正在改善...

  1. 浏览器供应商正在寻求删除蹦床。
  2. 通过接口类型建议,编码/解码开销将显着降低。

WebAssembly是一项非常新的技术,优化和解决性能问题需要时间。

这是否意味着 rust+wasm 不适合与 dom 操作频繁交互的 Web 开发。

目前,可能是的。在未来,这可能是可行的

我的分析正确吗?

你目前的观察,目前有点慢,是正确的。

相关内容

  • 没有找到相关文章

最新更新