Rust代码编译为WebAssembly模块(wasm文件)

WebAssembly是下一代Web客户端开发技术,目前已经是W3C的标准,94%的浏览器已经支持了WebAssembly标准。WebAssembly技术通过加载非Javascript语言(如C/C++、Rust、Go等)编写的源码经过交叉编译后生成的二进制文件,然后通过Javascript API调用相关函数完成计算,由于这些计算模块采用编译后的接近机器码的方式运行,因此WebAssembly技术可以让代码运行效率接近本机的运行效率,这大大提高了Web客户端程序的运行效率。当然,不建议使用WebAssembly操作浏览器DOM,否则运行效率可能会更低。
本文将使用一个Rust实现的计算指定位置的斐波那契数列值,对比Javascript实现和WebAssembly实现在运行效率上的差别。如果对Rust的安装及相关基本语法不了解,可参考本系列文档,可以从搭建开发环境开始学习。
斐波那契数列是这样一个数列:0、1、1、2、3、5、8、13、21、34、……。即:数列从0开始,然后第1、2项是1,然后从第 3 项开始,每一项都等于前两项之和。

1、安装wasm交叉编译器

在windows cmd或powershell窗口,执行以下命令安装交叉编译器:

rustup target add wasm32-unknown-unknown

2、创建Rust库项目

在windows cmd或powershell窗口,执行以下命令创建Rust库项目:

cargo new --lib hellowasm

修改Cargo.toml文件,将库类型修改为cdylib。在Cargo.toml文件的[dependencies]前添加以下内容:

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

删除文件lib.rs原有内容,修改为以下内容:

#[no_mangle]
pub extern fn fbin(x: i32) -> i32 {
    if x <= 1 {
        return 1;
    } else {
        return fbin(x - 1) + fbin(x - 2);
    }
}

no_mangle: 禁用对符号(symbol)名编码,表示在Javascript中依然采用fbin函数名调用本函数。extern关键字表示该函数可以在Javascript中调用。

3、编译为wasm文件

在hellowasm目录执行命令:

cargo build --release --target wasm32-unknown-unknown

编译成功后,会在hellowasm\target\wasm32-unknown-unknown\release目录中生成hellowasm.wasm文件。这个文件大小大概会超过1M,这是因为打包时cargo将所有依赖也添加到了.wasm文件中,否则可能该模块分发后不能正常运行。
将hellowasm.wasm文件copy到web服务器(如nginx、apache等,笔者采用的是npm的live-server)目录中即完成部署。

4、编写测试代码

<!DOCTYPE html>
<html lang="zh">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Rust WebAssemblydemo</title>
</head>

<body>
    <script>
        //JS实现的斐波那契数列
        function fnbin(x) {
            if (x <= 1) {
                return 1;
            } else {
                return fnbin(x - 1) + fnbin(x - 2);
            }
        }
        // 加载wasm文件函数
        function loadWebAssembly(fileName) {
            return fetch(fileName)
                .then(response => response.arrayBuffer())
                .then(buffer => WebAssembly.compile(buffer)) // 编译
                .then(module => { return WebAssembly.instantiate(module) }); //创建WebAssembly实例
        };

        //调用加载WebAssembly函数,注意wasm文件必须要本html文件在服务器同一目录,否则可能会出现404错误
        loadWebAssembly('hellowasm.wasm').then(instance => {
            console.time("WebAssembly")
            console.log(instance.exports.fbin(45))
            console.timeLog("WebAssembly");
            console.time("Javascript");
            console.log(fnbin(45))
            console.timeLog("Javascript")
        });
    </script>
</body>
</html>

打开浏览器(Chrome、FireFox等现代浏览器,而不是IE这种老古董),访问服务器页面,点击F12打开浏览器开发者工具观察程序输出。下图是笔者环境的某次运行结果:
运行结果

可以看到,WebAssembly的效率比Javascript的效率要高。

上一篇:Rust语言基础语法
下一篇:Rust面向对象编程

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容