WASM学习笔记

WebAssembly概念

webassembly是一种运行在现代web浏览器中的新型代码,不仅提供新的性能特性,同时还在性能方面有着巨大提升。它的涉及本意并非是提供开发者直接编译的代码,而是为诸如C,C++和Rust等源语言提供的一个有效的编译目标。

简单来说,你可以使用C,C++,Rust,Go等语言编写代码,然后编译为WebAssembly,在浏览器中运行。

编译C/C++为WebAssembly

Emscripten环境安装
所需条件
  • python
  • git
安装步骤
  1. 打开cmd,进入到软件将会安装到的目录下
  2. 输入 git clone https://github.com/emscripten-core/emsdk.git
  3. 输入 cd emsdk
  4. 输入 emsdk install latest
  5. 配置系统环境变量,依据下图操作

打开编译系统环境变量窗口,点击环境变量

最后一直点击每个未关闭窗口的确认即可。

具体使用

使用cmd打开需要被编译的C++文件夹,输入命令行emsdk activate (这仅仅会激活当前的环境,下次换另一个文件夹还需要再次激活),输入命令行emcc -v来检测配置是否成功,配置成功即可进入文件中书写代码。

代码编写完成后进入cmd窗口,输入命令行emcc 文件名 ,编译器就会对该文件进行编译.

当我们查看文件夹时,会发现多出来两个文件,一个是wasm格式的文件,一个是js格式的文件,前者是二进制文件,可以wasm2wat中打开该文件,后者放在html当中引入即可发现文件顺利转换且生效.

调用一个在C中的自定义方法

1.在文件夹下创建streaming文件夹,创建streaming.c文件,编写c语言代码

c 复制代码
#include <emscripten.h>

EMSCRIPTEN_KEEPALIVE
int sumOfNInts(int n)
{
    // return n*(n+1)/2;
    return my_div(mul(n,add(n,1)),2);
}

2.打开对应代码文件的cmd窗口,然后输入emcc streaming.c -o streaming.js

3.输入命令之后的效果如图所示

4.在html页面中调用c语言函数

  1. 实例化wasm模块
  2. 创建全局变量存储exports
  3. 使用exports来调用C语言函数
html 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
  </head>
  <body>
    <p>你好,WebAssembly!</p>
    <input type="number" id="a">
    <button onclick="run_wasm()">trigger触发</button>
    <p id="res"></p>
  </body>
  <script>
    // 创建变量来存储exports,使得可以全局访问
    let exports 
    // 实例化wasm模块
    WebAssembly.instantiateStreaming(
      fetch("streaming.wasm"),{}
    ).then(result => exports = result.instance.exports);

    function run_wasm(){

      let a = document.querySelector('#a').value;
      // 使用exports调用c语言函数
      let sum = exports.sumOfNInts(a);

      document.querySelector("#res")
        .innerHTML += `${a} => ${sum}<br/>`;

    }
  </script>
</html>
内存模型

1.使用js来操作wasm内存

  1. 初始化内存(设置内存大小,以及内存最大扩容量)
  2. 创造视图
    1. 使用typearray, 使用new关键字构造Uint32Array,不同类型数据需要使用不同的typearray,如数字类型数据需要使用Uint32Array,字符串类型需要使用Uint8Array;
    2. typearray(buffer:any,byteOffset?:number,length?:number)
    3. buffer指的是内存本身,byteOffset是偏移量,length是所需内存长度
  3. 通过视图操作内存
html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <p>你好,WebAssembly!</p>
  <input type="number" id="a">
  <button onclick="run_wasm()">trigger触发</button>
  <button onclick="getStr()">获取字符串</button>
  <p id="res"></p>
</body>
<script>
  let memeory = new WebAssembly.Memory({
    initial:256,
    maximum:512
  })
  // 创建变量来存储exports,使得可以全局访问
  let exports 
  WebAssembly.instantiateStreaming(
    fetch("memory.wasm"),{
      js:{
        mem:memeory
      }
    }
  ).then(result =>{ 
    exports = result.instance.exports;
    memory = result.instance.exports.memory;
  });
  
  function run_wasm(){
    let arr = new Uint32Array(memory.buffer);
    for(let i =0;i<10;i++){
      arr[i] = i*2;
    }

    let sum = exports.accumulate(0,10);
    
    document.querySelector("#res")
      .innerHTML += `${sum}<br>`;
  }

</script>
</html>

2.使用c语言来向内存中写入数据,然后js来调用c语言函数读取内存

c 复制代码
#include <emscripten.h>

int main()
{
    return 0;
}

EMSCRIPTEN_KEEPALIVE
const  char *getString()
{
    return "Hello,WebAssembly!"
}
javascript 复制代码
let memory = new WebAssembly.Memory({
  initial:256,
  maximum:512
})

let exports;
WebAssembly.instantiateStreaming(
  fetch("memory.wasm"),{
    js:{
      mem:memory
    }
  }
).then(result => {
  exports = result.instance.exports;
  memory = result.instance.exports.memory;
})

function getStr(){
  let ptr = exports.getString();
  let bytes = new Uint8Array(exports.buffer,ptr);
  let strlen = 0;
  while(bytes[strlen]){strlen++};

  let str = new TextDecoder("utf8").decode(
    bytes.slice(0,strlen)
  )
  console.log(str);
}
相关推荐
Starmoon_dhw11 小时前
题解:P17078 夏日甜点
c++·学习·算法·图论
菩提树下的打坐11 小时前
接口测试利器:REST Assured + WireMock
学习
一杯奶茶¥12 小时前
c语言程序设计大学期末考试考研知识点重点笔记题库复习资料C语言重点考点题库资料合集
c语言·笔记·考研·c语言程序设计·c语言笔记
FakeOccupational13 小时前
【电路笔记 信号】传输线方程:从RLGC推导传输线特性阻抗
笔记
tyqtyq2213 小时前
营养餐单规划:AI 科学饮食规划系统的鸿蒙实现
人工智能·学习·华为·职场和发展·生活·harmonyos
鱼听禅14 小时前
Ubuntu学习笔记-安装docker容器
学习·ubuntu·docker
Loving_enjoy15 小时前
DFT可测试性设计规则与检查:确保芯片可测试性的关键步骤
学习
r_oo_ki_e_15 小时前
Java反射机制学习笔记
java·笔记·学习
Nontee15 小时前
数据类型与包装类 — 一个新手学Java的数据类型笔记
java·笔记·python
ysa05103015 小时前
【板子】树上启发式合并
数据结构·c++·笔记·算法