在 Rust 程序和嵌入式 WebAssembly 运行时之间进行通信的最佳实践是啥?
Posted
技术标签:
【中文标题】在 Rust 程序和嵌入式 WebAssembly 运行时之间进行通信的最佳实践是啥?【英文标题】:What is the best practice to communicate between a Rust program and an embedded WebAssembly runtime?在 Rust 程序和嵌入式 WebAssembly 运行时之间进行通信的最佳实践是什么? 【发布时间】:2020-08-15 03:49:13 【问题描述】:我正在开发一个 Rust 程序,我想在运行时使用 WebAssembly 作为脚本语言来驱动其行为。我们假设脚本也是用 Rust 编写的。我已经阅读了 Wasmer、Wasmtime 和 Lucet 的教程,虽然导出/导入的函数可以作为参数并返回 WASM 原始类型,但似乎没有简单/无痛的解决方案可以在 Rust 二进制文件和 WASM 脚本之间传递任意数据在其中运行。特别是字符串,必须由manually passing a primitive as a sort of pointer 处理到运行时的线性内存和长度。
wasm-bindgen
似乎可以解决我的问题,但它只针对浏览器中的 WASM-JS 通信。 Wasmer 和 Wasmtime 有 *-interface-types
crates,但它们没有教程,并且是实验性的,可能会发生变化。我不需要通过struct
s,但我想实现这样的目标:
// in the host program
let argument: &[u8] = &[0, 1... n]; // dumb byte slice
let guest_result: Vec<u8> = wasm_runtime.call("guest_function", &[argument]);
// in the guest WASM library/script
let data_from_host: Vec<u8> = imported_function(some_other_bytes);
只需通过和返回Vec<u8>
s 或&[u8]
s 两种方式就足够了,我可以使用bincode
或其他方式反序列化它们。有没有人做到这一点?我可以像使用字符串一样共享线性内存,但这似乎不安全,尤其是在多个线程上使用多个脚本时。
tl;dr 我想使用 WASM 作为脚本语言并与 &[u8]
或 Vec<u8>
对话,但没有找到任何简单的方法。
【问题讨论】:
【参考方案1】:这个可用性问题是已知的,似乎正在积极处理中:https://hacks.mozilla.org/2019/08/webassembly-interface-types/
以下是该帖子中一些结束语的后续内容:https://github.com/bytecodealliance/wasmtime/issues/677
我几乎没有编写 C 或处理系统调用接口的经验,因此传递值对我来说也很麻烦。在大多数情况下,我只是花时间构建更高级别的抽象(就像 wasm-bindgen 所做的那样),以便我可以更轻松地传递数据。
例如,wasi 提供了一个您可以实现的接口,并且它们抽象出所有繁琐的部分:https://docs.rs/crate/wasi/0.9.0+wasi-snapshot-preview1/source/src/lib_generated.rs 您可以在此处看到 lucet 实现它:https://github.com/bytecodealliance/lucet/blob/master/lucet-wasi/src/runtime.rs
除非您尝试实现 wasi,否则我认为这不会对您有太大帮助,但它是实现您想要的那种抽象的一个很好的例子。
【讨论】:
以上是关于在 Rust 程序和嵌入式 WebAssembly 运行时之间进行通信的最佳实践是啥?的主要内容,如果未能解决你的问题,请参考以下文章
Rust & WebAssembly 翻译系列 为什么选择Rust和WebAssembly?
使用 Docker 管理用 Rust 编写的 WebAssembly 程序