大家好,很高兴又见面了,我是"高级前端进阶",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发!
什么是 GPU.js
GPU.js 是一个 JavaScript 加速库,用于 Web 和 Node.js 中的 GPGPU(General purpose computing on GPUs)。 GPU.js 自动将简单的 JavaScript 函数转换为着色器语言并编译以便在目标 GPU 上运行。如果 GPU 不可用,这些函数仍将在常规 JavaScript 中运行。
于 GPU.js 而言,对于底层环境的选择有一套完整的机制,从而能在浏览器和 NodeJS 环境中自行判断。比如,对于 Web 浏览器而言:
- 当 WebGL2 可用时,使用 WebGL2
- 当 WebGL2 不可用时,将使用 WebGL1
- 当 WebGL1 不可用时,将使用 CPU
对于 NodeJS 而言:
- 当 HeadlessGL 可用时,使用 HeadlessGL
- 当 HeadlessGL 不可用时,将使用 CPU
创建从 JavaScript 函数转译的 GPU 加速内核,该函数计算 512 x 512 矩阵(2D 数组)中的单个元素。 内核函数在 GPU 上串联运行,通常会产生非常快的计算! 感兴趣的开发者可以运行一个基准测试。 通常,GPU.js 的运行速度会快 1-15 倍,当然具体取决于目标硬件。
目前 GPU.js 在Github上通过MIT协议开源,有超过 14.8k的star、1k的fork、妥妥的前端优质开源项目。
GPU.js 为什么能更快
为了使 JavaScript 中的多线程数字计算更快,需要定义什么是“线程”。 在 JavaScript 中,假设有一个简单的函数来计算两个数组的乘法点积:
function multiplyMatrixes(a, b) {
const width = a.length;
const height = b.length;
const result = new Array(height);
for (let y = 0; y < height; y++) {
const row = new Float32Array(width);
for (let x = 0; x < width; x++) {
let sum = 0;
for (let i = 0; i < width; i++) {
sum += a[y][i] * b[i][x];
}
row[x] = sum;
}
result[y] = row;
}
return result;
}
// multiplyMatrixes(a, b);
这里的“线程”是可操作的计算,比如下面的核心部分:
let sum = 0;
for (let i = 0; i < width; i++) {
sum += a[y][i] * b[i][x];
}
row[x] = sum;
看看如何不包括计算 x 和 y 的循环吗? 这是因为在 GPU 上,这些值是串联(calculated in tandem)或同时计算的,x 可能同时存在多个不同的数字,但在不同的线程中执行相同的代码。
同时需要注意的是,GPU 实际上并不比 CPU 快多少(如果有的话),但同时执行指令集,因此实际上节省了时间。每个线程都不知道其他线程中发生了什么,只是计算一个值并返回。
就像计算机如何计算显示单个像素所需的信息,像素是根据红色、绿色、蓝色和 Alpha 计算得出的值,每个像素只知道它“触摸”的视觉效果。
如果想在 GPU 上执行相同的计算,因为内核函数作为循环或线程运行,所以省略循环并本质上进行相同的计算。 在 GPU.js 中,x 和 y(还有 z 等等)是通过使用 this.thread.x 或 this.thread.y(或 this.thread.z)获得的。 这是上面相同函数的 GPU.js 版本:
const multiplyMatrixes = gpu.createKernel(function(a, b) {
let sum = 0;
for (let i = 0; i < this.constants.width; i++) {
sum += a[this.thread.y][i] * b[i][this.thread.x];
}
return sum;
})
.setOutput([width, height])
.setConstants({
width:
});
// multiplyMatrixes(a, b);
如何使用 GPU.js
在浏览器环境中可以通过下面的代码轻松调用 GPU.js 的能力:
<script src="dist/gpu-browser.min.js"></script>
<script>
// GPU is a constructor and namespace for browser
const gpu = new GPU();
const multiplyMatrix = gpu.createKernel(function(a, b) {
let sum = 0;
for (let i = 0; i < 512; i++) {
sum += a[this.thread.y][i] * b[i][this.thread.x];
}
return sum;
}).setOutput([512, 512]);
const c = multiplyMatrix(a, b);
</script>
如果在 Node.js 环境中,需要安装相应的包然后调用即可:
const { GPU } = require('gpu.js');
const gpu = new GPU();
const multiplyMatrix = gpu
.createKernel(function (a, b) {
let sum = 0;
for (let i = 0; i < 512; i++) {
sum += a[this.thread.y][i] * b[i][this.thread.x];
}
return sum;
})
.setOutput([512, 512]);
const c = multiplyMatrix(a, b);
更多关于 GPU.js 的用法本文不再过多展开,大家可以自行阅读文末的参考资料。
参考资料
https://github.com/gpujs/gpu.js/wiki/Quick-Concepts
https://github.com/gpujs/gpu.js/#gpucreatekernel-settings
https://blog.bitsrc.io/using-gpu-to-improve-javascript-performance-e5a41c2e129b
https://gpu.rocks/#/
本文暂时没有评论,来添加一个吧(●'◡'●)