2021-05-10 07:28

用Wasm连接Rust与Python | Rust 学习笔记(三)

本文是"Rust 学习笔记"系列的第三篇。其他两篇请见文末。

本篇是魔改出一个 Encoder | Rust 学习笔记(一)注1的进一步延伸,在那一篇中,我们借助 Yew 和 Trunk,对 Wasm 进行了"快速上手实践"。

代码见:

https://github.com/leeduckgo/Rust-Study/tree/main/b64-encoder

但是,在浏览器中运行只是 Wasm 的玩法之一:

WebAssembly 是一种新的编码方式,可以在现代的网络浏览器中运行 - 它是一种低级的类汇编语言,具有紧凑的二进制格式,可以接近原生的性能运行,并为诸如 C / C ++ 等语言提供一个编译目标,以便它们可以在 Web 上运行。它也被设计为可以与 JavaScript 共存,允许两者一起工作。

简而言之,对于网络平台而言,WebAssembly 具有巨大的意义——它提供了一条途径,以使得以各种语言编写的代码都可以以接近原生的速度在 Web 中运行。在这种情况下,以前无法以此方式运行的客户端软件都将可以运行在 Web 中。

Wasm 还有另一种套玩法 —— 我们可以将 WASM 作为普通程序运行,也可以成为其他编程语言的模块,这也是本文所要讨论的。

作为普通程序/普通模块,Wasm 具有如下两点 AmAzING 的特性:


1.安全访问


你现在找到的大部分 WebAssembly 教程和例子都是聚焦在浏览器之中,比如如何加速网页或者网页应用各种各样的功能。无论如何,WebAssembly 真正强大的领域但是被提及的很少:浏览器之外的领域;也是我们接下来系列关注的点。

浏览器之外,它的主要优势就是可以用不用妥协安全的前提下提供系统级别的访问。它是通过 WASI 完成的;Web Assembly System Interface(WASI 全称,大致意思就是 WebAssembly 系统接口)是一个类 C 的函数集,在安全的方式提供功能性的系统访问,如 fd_read、rand、fd_write、线程(WIP) 等等。

这里举出一些你可能使用的场景(当然是非浏览器场景):

  • 视频游戏的脚本语言;
  • 最低负载运行代码,就像 Fastly/Cloudflare 的边缘计算(compute-at-edge)场景;
  • 最低运行负载在 IOT 设备安全地运行易于更新的代码;
  • 不需要 JIT 就能在你的环境中获取极快的性能;
https://n3xtchen.github.io/n3xtchen/rust/2020/08/17/webassembly-without-the-browser-part1


2.让不同的编程语言程序之间更自由的调用


作为一种"低级语言",Wasm程序可以很好的成为不同编程语言程序之间沟通的桥梁,同时避免了在一台服务器上安装多种语言的环境。

例如,我们可以在 Python 中调用用Wasm程序写的模块:

https://github.com/bytecodealliance/wasmtime-py

现在,让我们开始实践之旅吧!

注:本文对如下内容有所参考——
https://zhuanlan.zhihu.com/p/352196567




1 创建 Rust Lib 程序


在之前的文章中,我们通过如下命令创建一个 Rust 项目。

cargo new foobar

然而,有的时候,我们希望创建一个库,以供其他程序进行调用,如本节课我们要生成与调用的wasm程序,即是一个库。

我们通过加上--lib 参数以生成一个库项目。

cargo new --lib adder

实际上,你去探索上述命令行生成的文件,发现它们的 Cargo.toml 完全一样,区别仅在于 src 目录下,可执行工程是一个 main.rs,而库工程是一个 lib.rs。


2 完善 Rust Lib 程序


用如下代码替换lib.rs的内容:

#[no_mangle]pub extern "C" fn adder(a: i32, b: i32) -> i32 { a + b}

这段代码中的关键是#[no_mangle]

#[no_mangle]告诉Rust编译器不要修改函数名称,这样我们才能在其他程序中通过函数名调用生成的Wasm,不写会生成 _ZN4rustfn1_34544tert54grt5 类似的混淆名。

Cargo.toml文件中,我们添加如下代码:

[lib]crate-type = ['cdylib']

这两行代码表示我们编译时将会生成系统库,以供其他编程语言的程序调用。


3 编译为 Wasm 模块


执行如下命令:

cargo build --release --target wasm32-wasi

执行成功后,我们将在target/wasm32-wasi/release目录下看到adder.wasm文件。

4 通过 Python 调用 Wasm

这里我们选择这个Python库:

https://github.com/wasmerio/wasmer-python

安装库:

pip3 install wasmer==1.0.0pip3 install wasmer_compiler_cranelift==1.0.0

调用:

确保我们在target/wasm32-wasi/release目录下。

打开python或者ipython

输入:

from wasmer import engine, Store, Module, Instancefrom wasmer_compiler_cranelift import Compiler

# Let's define the store, that holds the engine, that holds the compiler.store = Store(engine.JIT(Compiler))

# Let's compile the module to be able to execute it!module = Module(store, open('adder.wasm', 'rb').read())

# Now the module is compiled, we can instantiate it.
instance = Instance(module)


# Call the exported `sum` function.
result = instance.exports.adder(5, 37)

print(result) # 42!


5 示例代码


本系列所有源码在如下Repo 中开源:

https://github.com/leeduckgo/Rust-Study

在该目录下,用本教程方法编译,安装必要的 Python 包,然后执行:

python3 run_adder.py

即可看到效果。

点击链接查看本系列代码:https://github.com/leeduckgo/Rust-Study

本文链接:https://www.8btc.com/media/6632324
转载请注明文章出处

评论
登录 账号发表你的看法,还没有账号?立即免费 注册
下载
阅读
分享
评论
点赞
上一篇
下一篇