• 作者:老汪软件技巧
  • 发表时间:2024-08-21 15:03
  • 浏览量:

引言

在现代 Web 开发中,将高性能计算和智能分析集成到前端应用中已经成为一种趋势。本文将介绍在超大型远洋航运颗/货船舶管理系统中,借助于 Rust 和 AI 技术实现 Web 侧 端智能数据分析处理海量传感器数据进行可视化界面的渲染工作,通过一系列的数据清洗、转换和分析,提升用户体验。

背景数据分析与预处理的需求

在现代 Web 应用中,特别是在数据密集型的应用场景下,处理和展示海量数据是一项具有挑战性的任务。传统的前端技术堆栈,如 JavaScript 和框架库,虽然能提供基本的数据处理功能,但在面对复杂的数据分析任务时可能显得力不从心。这些任务包括数据清洗、转换、聚合、以及实时分析等。

随着数据规模的增大和分析需求的复杂化,前端应用需要能够高效地处理大量数据,同时保持良好的用户体验。例如,电商平台需要实时处理用户行为数据来提供个性化推荐,社交媒体应用需要分析用户生成内容以进行情感分析,金融应用则需要实时处理市场数据以进行预测和决策支持。

技术挑战

在浏览器环境中进行复杂的数据处理面临几个主要挑战:

Rust 与 WebAssembly 的优势

为了应对这些挑战,Rust 和 WebAssembly (WASM) 的组合提供了一种解决方案。Rust 是一种系统编程语言,具有高效的内存管理和高性能的计算能力。WebAssembly 是一种可以在浏览器中运行的低级字节码格式,它允许开发者用非 JavaScript 语言编写代码,并将其编译为可以在浏览器中执行的高效二进制格式。

主要脉络

熟悉或者已经阅读过 Mdn 上面关于如何实现“Compiling from Rust to WebAssembly”的小伙伴可以跳过前面这一部分。

环境准备

无需过多心理压力,本文中的代码会尽可能得将注释和用意阐述清晰完整,纵使对于 Rust 这门编程语言一窍不通的读者也不会有过多的阅读障碍。

首先我们需要安装 Rust 和 WebAssembly 工具链:

# 安装 Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# 安装 wasm-pack
cargo install wasm-pack
# add WebAssembly target
rustup target add wasm32-unknown-unknown

此处对于不同操作系统的 PC 如何安装 Rust 可以参考…

wasm-pack,由于我们需要打包工具,所有这里引出了一个额外的工具--wasm-pack,有了 wasm-pack,我们可以将 rust code 编译为 WebAssembly,供给 WEB 端进行调用;

Rust 项目初始化

接下来我们在命令行输入类似于如下的命令:

cargo new --lib your-rust-project

此处为了方面演示,使用了 cargo new --lib rust-social-emotion-analysis 这个名称作为 Rust 项目根目录在 cargo new --lib your-rust-project 命令执行过后,我们会看到本地多出了以下几个文件:

├── Cargo.toml
└── src
└── lib.rs

这里我们可以使用 Cargo.toml 对构建进行配置,Cargo.toml 类似于前端工程的 package.json 文件。

cd src,进入到 src 目录中之后,我们会发现 lib.rs 内部的几行代码:

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
        assert_eq!(2 + 2, 4);
    }
}

这部分代码直接删除即可,然后替换为我们需要的 demo code:

// 引入 wasm_bindgen 库,这允许 Rust 代码与 WebAssembly 的 JavaScript 进行无缝交互
use wasm_bindgen::prelude::*;
// 使用 #[wasm_bindgen] 属性声明外部 JavaScript 函数
// 这里声明了一个名为 `alert` 的函数,该函数会在浏览器中弹出alert框
#[wasm_bindgen]
extern {
    // 外部函数 `alert`,用于显示alert对话框,接受一个字符串参数
    // 在浏览器环境中,这会弹出一个alert框显示传入的消息
    pub fn alert(s: &str);
}
// 使用 #[wasm_bindgen] 属性公开 Rust 函数,使其可被 JavaScript 代码调用
// 这个函数将用于向用户打招呼
#[wasm_bindgen]
pub fn greet(name: &str) {
    // 使用 Rust 的 `format!` 宏创建一个格式化的greet字符串
    // `format!` 宏将 `name` 参数插入到字符串中,生成类似 "Hello, John!" 的greet信息
    // 调用外部的 `alert` 函数来弹出显示该greet信息
    alert(&format!("Hello, {}!", name));
}

这里之所以引入 wasm_bindgen 这一 Crate 的原因是 wasm-pack 需要借助于 wasm-bindgen 来生成桥接 Javascript 与 Rust 的代码,进而使得我们可以在 JS 中调用 Rust API 或者 Rust 函数。

配置 Cargo.toml

打开项目的 cargo.toml 文件按照如下进行配置:

[package]
name = "hello-wasm"
version = "0.1.0"
authors = ["Your Name "]
description = "A sample project with wasm-pack"
license = "MIT/Apache-2.0"
repository = "https://github.com/yourgithubusername/hello-wasm"
edition = "2018"
[lib]
crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = "0.2"

通过以上代码,首先我们添加了[package],其次通过[lib]这一部分是为了告知 Rust 我们想要打包成 cdylib 的版本。最后的[dependencies]是为了让 Cargo 知道我们依赖于 wasm-bindgen 0.2.x 版本。

构建

这里我们通过以下一段简短的命令进行构建:

wasm-pack build --target web

根据 Mozilla Hacks 上面的描述,简而言之以上代码大致做了以下五件事:

截至目前为止,我们的 Rust 项目目录基本如下:

├── Cargo.lock
├── Cargo.toml
├── index.html  <-- 新建一个 index.html 文件放置于Rust工程的根目录
├── pkg
│   ├── hello_wasm.d.ts
│   ├── hello_wasm.js
│   ├── hello_wasm_bg.wasm
│   ├── hello_wasm_bg.wasm.d.ts
│   └── package.json
├── src
│   └── lib.rs
└── target
    ├── CACHEDIR.TAG
    ├── release
    └── wasm32-unknown-unknown

在根目录新建一个 index.html 文件,并在其中编写如下代码:

_智能前端系统_前端集成解决方案

html>
<html lang="en-US">
  <head>
    <meta charset="utf-8" />
    <title>hello-wasm exampletitle>
  head>
  <body>
    <script type="module">
      import init, { greet } from "./pkg/hello_wasm.js";
      init().then(() => {
        greet("WebAssembly");
      });
    script>
  body>
html>

OK,现在我们可以借助于 http-server 启动一个本地的静态资源服务,浏览页面效果:

npx http-server

至此,我们的第一步,即--“将 Rust Code 编译为 WASM,编译为 WebAssembly 并在 WEB 端集成”基本实现完成了。这部分为了方面演示省略了很多譬如压缩 Rust 转化为 WASM 文件的体积、以及老生常谈的 Rust 所有权和借用系统。

接下来我们看一下如何借助于 rust 实现海量数据的预处理与数据分析工作,以满足我们页面可视化渲染相关的需求。

大批量数据的预处理与分析

这一部分我们将重点讨论如何使用 Rust 的并发特性来提高数据处理的效率,并将结果集成到 WebAssembly 中以用于浏览器端的数据分析。

引入所需的库

// 引入 wasm-bindgen 库的预处理模块,用于与 JavaScript 交互
use wasm_bindgen::prelude::*;

定义数据结构

// 定义一个结构体来表示传感器数据项
// 结构体包含一个 id 和一个值,分别表示数据项的唯一标识符和传感器读取的值
#[derive(Clone, Debug)]
struct SensorData {
    id: u32,
    value: f64,
}

基础数据预处理

// 通过一个函数来对数据进行预处理,例如筛选出值大于某个阈值的数据
#[wasm_bindgen]
pub fn preprocess_sensor_data(data: &[SensorData], threshold: f64) -> Vec {
    // 使用迭代器和过滤方法筛选出符合条件的数据
    data.iter()
      .filter(|item| item.value > threshold)
      .cloned()
      .collect()
}

并发数据预处理

为了提高处理海量数据的效率,我们可以利用 Rust 的并发特性。使用 rayon 库,可以轻松实现数据的并行处理。

首先,添加 rayon 依赖到 Cargo.toml:

[dependencies]
wasm-bindgen = "0.2"
rayon = "1.5" // 添加 rayon 依赖

接下来,修改数据预处理函数以利用并发处理:

// 引入 rayon 库
use rayon::prelude::*;
// 并发数据预处理逻辑
#[wasm_bindgen]
pub fn parallel_preprocess_sensor_data(data: &[SensorData], threshold: f64) -> Vec {
    // 使用 rayon 的并行迭代器来加速数据预处理
    data.par_iter() // 使用并行迭代器
      .filter(|item| item.value > threshold)
      .cloned()
      .collect()
}

这里主要做了两件事:

数据分析

基础数据分析:

// 对数据进行分析,例如计算数据的平均值
#[wasm_bindgen]
pub fn analyze_sensor_data(data: &[SensorData]) -> f64 {
    // 计算总和
    let sum: f64 = data.iter().map(|item| item.value).sum();
    // 计算平均值
    sum / data.len() as f64
}

并发数据分析

对于大数据集的并发分析,特别是需要进行复杂计算时,利用并发可以显著提高性能:

// 引入 rayon 库
use rayon::prelude::*;
// 并发分析计算数据的标准差
#[wasm_bindgen]
pub fn parallel_analyze_sensor_data(data: &[SensorData]) -> f64 {
    // 使用 rayon 的并行迭代器来加速数据分析
    let mean = analyze_sensor_data(data);
    let variance: f64 = data.par_iter() // 使用并行迭代器
      .map(|item| (item.value - mean).powi(2)) // 计算每个数据点与均值的平方差
      .sum(); // 汇总平方差
    // 计算标准差
    (variance / data.len() as f64).sqrt()
}

与前端工程的 Webpack 集成

在项目的 webpack.config.js 类似的配置文件中,添加 WebAssembly 支持:

const path = require("path");
const WasmPackPlugin = require("@wasm-tool/wasm-pack-plugin");
module.exports = {
  configureWebpack: {
    plugins: [
      new WasmPackPlugin({
        crateDirectory: path.resolve(__dirname, "rust_data_processing"),
      }),
    ],
    experiments: {
      asyncWebAssembly: true,
    },
  },
};

在 Vue 项目中的调用:

<template>
  <div>
    <h1>数据分析h1>
    <p>预处理后的数据: {{ processedData }}p>
    <p>分析结果: {{ analysisResult }}p>
  div>
template>
<script lang="ts">
import { defineComponent, onMounted, ref } from 'vue';
import init, { parallel_preprocess_sensor_data, parallel_analyze_sensor_data } from 'rust_data_processing';
export default defineComponent({
  setup() {
    const processedData = ref<SensorData[]>([]);
    const analysisResult = refnull>(null);
    onMounted(async () => {
      await init(); // 初始化 WebAssembly 模块
      const rawData: SensorData[] = [/* 海量传感器数据 */];
      const threshold = 10.0;
      // 预处理数据
      processedData.value = parallel_preprocess_sensor_data(rawData, threshold);
      // 分析数据
      analysisResult.value = parallel_analyze_sensor_data(processedData.value);
    });
    return { processedData, analysisResult };
  },
});
script>
<style scoped>
/* 样式 */
style>

端侧 AI 能力探索

这一部分我们主要探索如何编写数据处理代码

定义数据结构和实现数据预处理功能,例如数据标准化和特征提取:

// 引入必要的库
use wasm_bindgen::prelude::*;
use ndarray::Array2;
use ndarray_rand::RandomExt;
use ndarray_rand::rand_distr::Uniform;
// 定义数据结构
#[derive(Debug, Clone)]
pub struct SensorData {
    id: u32,
    value: f64,
}
// 实现数据预处理函数
#[wasm_bindgen]
pub fn preprocess_sensor_data(data: &[SensorData], threshold: f64) -> Vec {
    // 过滤掉值低于阈值的数据
    data.iter()
        .filter(|item| item.value > threshold)
        .cloned()
        .collect()
}

K-Means 聚类是一种广泛使用的无监督学习算法,用于将数据分组为 K 个簇。一个 Rust 实现的 K-Means 聚类库,适用于高性能计算。Rust 版 K-Means 实现主要有Rust K-Means —- Rust 实现的 K-Means 聚类库,适用于高性能计算以及rust-kmeans -- Crates.io 上的 rust-kmeans 库,可用于 K-Means 聚类算法的实现。

此处我们使用 ndarray 实现基本的聚类算法(K-Means)作为数据分析的一部分:

// 引入必要的库
use wasm_bindgen::prelude::*;
use ndarray::Array2;
use ndarray_rand::RandomExt;
use ndarray_rand::rand_distr::Uniform;
// 定义数据结构
#[derive(Debug, Clone)]
pub struct SensorData {
    id: u32,
    value: f64,
}
// 数据预处理
#[wasm_bindgen]
pub fn preprocess_sensor_data(data: &[SensorData], threshold: f64) -> Vec {
    // 过滤掉值低于阈值的数据
    data.iter()
        .filter(|item| item.value > threshold)
        .cloned()
        .collect()
}

结语

本文主要探索了如何利用 Rust 和 WebAssembly 的组合,将数据处理能力引入 Web 端。通过 Rust 的并发计算和 WASM 的高执行效率优势,尝试克服传统 JavaScript 的性能瓶颈,进而实现了在浏览器中进行复杂数据分析的可能性。随着 AI 快速发展的当下,Rust + WASM 凭借着高并发、高执行效率以及跨平台的优势,将会是端智能甚至是边缘计算中一个非常不错的选择。

参考文档