WebAssembly的使用

WebAssembly的使用

介绍

WebAssembly(缩写为Wasm)是基于堆栈的虚拟机的二进制指令格式。Wasm被设计为可移植目标,用于编译高级语言(如C / C ++ / Rust),从而可以在Web上为客户端和服务器应用程序进行部署。

webassembly的背景

我们为什么需要wasm?它可以解决什么问题?

javascript从最开始诞生起,它的定位就是一门解释性语言,它面向的开发者是“非专业编程人员”,学习门槛很低。谁也想不到这门语言现在变成了互联网上最重要的语言之一,它在浏览器应用中的地位不可撼动。 随着互联网的发展,需求场景变得越来越复杂,js的性能问题也暴露了出来。往往当一门语言对开发者越友好,那它对机器也就越不友好。机器编译它的难度,所耗费的精力也就越高。

而WebAssembly的出现,有望解决这一难题。 WebAssembly它是一种新的字节码格式,和JS需要解释执行不同,WebAssembly的字节码它与机器码很相似,可以快速转换并装载运行,因此,它的性能相对于JS会有大大的提升。严格意义上来讲,它并不能算是一种新语言,也不需要开发者们去编写WASM代码,它是一份字节码标准。我们只需要将一些高级语言编译为wasm字节码,然后在web中使用。现在wasm的使用方式主要还是在js中引入,所以可以看出,它与JS并不是替代关系,而是合作关系。在一些需要高性能的场景下,JS做不到,那我们就可以引入wasm字节码来解决。

安装环境

在windows环境下构建WebAssembly的工具链Emscripten

在开始构建安装之前,你需要确保你本地已经安装好了以下的工具:

  • Git
  • CMake
  • Python 2.7.x

一切准备就绪后,就可以通过Emscripten SDK来构建Emscripten了。步骤如下: 1. git clone https://github.com/emscripten-core/emsdk.git 2. cd emsdk 3. git pull 4. ./emsdk install latest 5. ./emsdk activate latest 6. emsdk_env.bat

其中最关键的是第四步,也是比较耗时的一步,耐心等待吧。 安装好了之后,需要注意的是每次重新打开命令行控制台后,都需要进行第5、6步骤, 才能正常使用Emscripten工具来编译。可以通过命令emcc -v来检测。结果如下则表示安装成功可以正常使用:

PS D:\webAssemblyDemo\emsdk> emcc -v
emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 1.39.4
clang version 10.0.0 (Cswircachegitchromium.googlesource.com-external-github.com-llvm-llvm--project b5f295ffcec2fa7402e39eb1262acbd55a7d39f5)
Target: x86_64-pc-windows-msvc
Thread model: posix
InstalledDir: D:/webAssemblyDemo/emsdk/upstream/bin
shared:INFO: (Emscripten: Running sanity checks)

可以看到emcc版本为1.39.4 ,一般按照上面步骤正常操作的话版本都没有问题,但如果你的版本在1.37或更低,那你就需要注意了: >emcc 在 1.37 以上版本才支持直接生成 wasm 文件。

开始一个简单的Demo

参考官方给出的demo来进行WebAssembly的初试:编写一个简单的C程序,使用emcc命令将其进行编译,最后在浏览器中运行。

• 在使用emcc命令时,要带着 -s WASM=1参数(不然,默认会编译成asm.js) • 如果我们想让Emscripten生成一个我们所写程序的HTML页面,并带有wasm和JavaScript文件,我们需要给 输出的文件名加.html后缀名。 • 最后,当我们运行程序的时候,我们不能直接在浏览器中打开HTML文件,因为跨域请求是不支持file协议的,我们需要将我们的文件输出在http协议上。

demo步骤如下:

编写C程序文件jnshu.c如下:

  •  #include<stdio.h>
     int main(int argc,char ** argv){
     printf("www.jnshu.com");
     }

使用命令emcc jnshu.c -s WASM=1 -o  jnshu.html编译文件 编译后会生成 jnshu.html、 jnshu.wasm、 jnshu.js三个文件

使用emrum命令来创建一个http协议的web server来展示编译后的文件 emrun --no_browser --port 8080  .\jnshu.html

通过浏览器来访问

可以看到C程序打印的官网地址已经成功的在控制台上展示。

通过javascript来调用wasm文件

重新写一个C程序:

#include<stdio.h>
int square(int x){
    return x * x;
}

int add (int x, int y){
    return x + x;
}

这次的程序中没有main函数,只有两个方法。接下来使用emcc命令将其编译为wasm文件,并在js中调用它。

使用下面的命令直接将c编译为wasm文件: emcc .\last.c -Os -s WASM=1 -s SIDE_MODULE=1 -o last.wasm

 以十六进制编码的方式打开查看这个二进制文件:

 它的开头几位为 20 61 73 6D,这个是判断一个文件是否符合wasm格式的标准。 它对应的ASCII码为: asm 之前说了emcc 在 1.37 以上版本才支持直接生成 wasm 文件。低版本通过命令貌似也可以生成一个后缀为.wasm的文件,编译过程不会报错。但在浏览器中调用wasm文件时就会报出wasm文件首部编码不匹配的问题。

有了wasm文件后,就可以在js中调用它了。 下面给出加载wasm模块的方法,这也是官方目前最为推荐的一种方式。 使用fetchAndInstantiate方法来获取WebAssembly模块,并将其实例化:

function fetchAndInstantiate(url, importObject={}) {
  return fetch(url).then(response =>
    response.arrayBuffer()
  ).then(bytes =>
    WebAssembly.instantiate(bytes, importObject)
  ).then(results =>
    results.instance
  );
}

js得到wasm实例后,就可以使用webAssembly.Instance.exports导出的方法了。

fetchAndInstantiate('math.wasm').then(function(instance) {
 //调用导出的函数
 var add = instance.exports.add
 var square = instance.exports.square
 console.log('1+1=',add(1,1))
 console.log('2*2=',square(2))
})

math.wasm需要与math.js在同一路径下。 最后将这段js代码加入math.html中,并通过htttp来访问:

如果你的浏览器是Firefox 54+的话, 其Developer Tool Debugger Panel模式可以将网页中包含的任何 wasm 代码转换为文本格式(wat),如下:

(export "add" $func1),(export "square" $func1)可以看到C程序中的两个方法被导出为add,square。这个很关键。看了很多教程,大家在使用如上方法调用wasm模块时,默认给方法名前加_, 如:var add = instance.exports._add。在低版本好像是这样的,导致我在升级版本后,调用模块总是提示没有此方法。查看了wasm的文本后才明白,新版直接调用方法名就可以了。

WebAssembly与JavaScript的性能对比

分别使用这两种语言来计算斐波那契数列,对比它们的运行时间。为了使效果显著,计算函数重复执行一百万次,每次计算到斐波那契数列的第46项。 C代码如下:

void fib(int n)
{
    int first = 0, second = 1, sum;
    for (int i = 0; i < n; i++)
    {
        sum = first + second;
        first = second;
        second = sum;
    }
}

对C程序进行编译生成 fib.wasm emcc .\fib.c -Os -s WASM=1 -s SIDE_MODULE=1 -o fib.wasm 在js中调用该模块,并打印函数执行时间。 代码如下:

function fetchAndInstantiate(url, importObject={}) {
      return fetch(url).then(response =>
        response.arrayBuffer()
      ).then(bytes =>
        WebAssembly.instantiate(bytes, importObject)
      ).then(results =>
        results.instance
      );
    }
    
function fib_js(n) {
    let first = 0, second = 1, next;
    for (let i = 0; i < n; i++)
    {
        next = first + second;
        first = second;
        second = next;
    }
    return second;
}
    


 fetchAndInstantiate('fib.wasm').then(function(instance) {
     //调用导出的函数
     var fib_wasm = instance.exports.fib
     
     var start_js = new Date();
     for (var i = 0; i < 1000000; i++) {
         fib_js(46);
     }
     console.log('js_time:', new Date() - start_js);
     
     var start_wasm = new Date();
     for (var i = 0; i < 1000000; i++) {
         fib_wasm(46);
     }
     console.log('wasm_time:', new Date() - start_wasm );
     
    })
    

在浏览器中运行,查看打印出的时间:

 可以看到两者在计算复杂型任务中的效率差距还是很大的。

webassembly未来的应用场景有哪些?

既然webassembly是来解决性能问题的,那么在未来,浏览器端一些计算密集型的场景,webassembly都可以插足进来。 ## 音视频领域 JavaScript的运行时性能问题导致浏览器处理音视频的能力不足。 WebAssembly 技术历经 3 年的发展已经日臻成熟,主流浏览器厂商都已提供了对 Webassemly 的支持。可以预见 WebAssembly 能让音视频技术和 Web 前端开发更完美的结合在一起。

AutoCAD

这是一款经典的画图软件,但却没有Web版本。 原因有两个: 其一,是Web的性能的确不能满足他们的需求。 其二,在WebAssembly没有面世之前,AutoCAD是用C++实现的,要将其搬到Web上,就意味着要重写他们所有的代码,这代价十分的巨大。 而在WebAssembly面世之后,AutoCAD得以利用编译器,将其沉淀了30多年的旧代码直接编译成WebAssembly,同时性能基于之前的普通Web应用得到了很大的提升。正是这些原因,得以让AutoCAD将其应用从Desktop搬到Web中。

Google Earth

Google Earth也就是谷歌地球,因为需要展示很多3D的图像,对性能要求十分高,所以采取了一些Native的技术。最初的时候就连Google Chrome浏览器都不支持Web的版本,需要单独下载Google Earth的Destop应用。而在WebAssembly之后呢,谷歌地球推出了Web的版本。而据说下一个可以运行谷歌地球的浏览器是FireFox。

文章中所有的代码已整理放入github仓库: https://github.com/zln312/webassembly_demo.git

参考官方文档: https://webassembly.org/getting-started/developers-guide/ https://emscripten.org/docs/getting_started/downloads.html 参考链接: WebAssembly完全入门——了解wasm的前世今身 https://www.cnblogs.com/detectiveHLH/p/9928915.html

今天的分享就到这里啦,欢迎大家点赞、转发、留言、拍砖

------------------------------------------------------------------------------------------------------------

“我们相信人人都可以成为一个工程师,现在开始,找个师兄,带你入门,学习的路上不再迷茫。”

技能树·IT修真院:https://www.jnshu.com

发布了750 篇原创文章 · 获赞 1052 · 访问量 58万+

猜你喜欢

转载自blog.csdn.net/jnshu_it/article/details/103745500