万维网网站电商网站适合做响应式布局吗
万维网网站,电商网站适合做响应式布局吗,西安小程序开发费用,263邮箱登录入口官网1.WebAssembly
1.1 指令集 概念#xff1a;二进制编码集合。 依据计算机组成原理和计算机概论#xff0c;指令集是一组二进制编码。 作用#xff1a;控制硬件。 这些二进制指令直接作用于硬件电路#xff0c;控制硬件完成指定操作。 例如#xff1a;控制数据进入某个寄存…1.WebAssembly
1.1 指令集 概念二进制编码集合。 依据计算机组成原理和计算机概论指令集是一组二进制编码。 作用控制硬件。 这些二进制指令直接作用于硬件电路控制硬件完成指定操作。 例如控制数据进入某个寄存器控制数据做位运算。 分类 按CPU分类。 不同架构的CPU有不同的指令集。 例如x86和arm架构CPU指令集不同。 1.2 WebAssembly 概念低级静态程序语言。 WebAssembly可以看做是针对于浏览器的一组指令集。它是低级程序语言。 例如它和汇编语言类似只不过不同CPU的汇编语言不同但是不同浏览器的WebAssembly都相同。 作用在浏览器中运行。 除了JavaScript外另一种可以直接在浏览器中运行的语言。 例如因为WebAssembly可以在浏览器中运行因此C/CRust等语言选择把它们编译成WebAssembly在浏览器运行。 特点效率高。 不需要通过高级程序员的解释器或编译器是编译产物免去这个耗时操作。 例如高级程序语言的一系列操作可以被汇编级语言优化成几次简单操作例如优化后简单将数据在寄存器间移动就可能完成多个语句表示的操作。 2.优化密集计算型业务
2.1 编译流程概述 流程背景 编译C/C指定函数到wasm文件为JavaScript提供计算密集型任务的高效解决方案。 流程概述 按照emscripten官方文档安装编译器并对C/C打包。 注也可以编译整个C/C文件到wasm本流程只导出函数 激活环境 运行 emsdk_env.bat和 emsdk_env.sh激活编译器环境 编译 运行 emcc test1.cpp -s EXPORTED_FUNCTIONS_fib,_add -O3 -o fib-emcc.wasm编译成wasm文件 命令说明 注官网上提到过导出cwrapccall来给JavaScript调用导出的C/C函数。但是安装最新版emscripten发现没用。 -s EXPORTED_FUNCTIONS 指明导出的C/C函数函数名前需要加下划线-O 指明编译优化方案和g中 -O指令含义相同 2.2 编译流程详解
2.2.1 C/C部分 extern C连接指示符 按C语言规则来处理函数名称。Emscripten要求导出C函数时必须有该操作。 main函数 Emscripten要求导出C/C函数时即使不导出main函数也要必须写main函数。 开辟内存和写入内存函数 JavaScript传入引用类型给Wasm模块时直接传入会失败。因为C中引用类型需要指明指针地址如果JavaScript需要传入引用类型需要在Wasm模块中开辟一块空间写入传入的参数这样C才能访问到。如果传入普通类型不需要考虑开辟空间。 #includealgorithmextern C {// 将导出给JavaScriptab函数int add(int a, int b) {return a b;}// 将导出给JavaScript开辟内存空间函数int* createIntArray(int length) {return new int[length];}// 将导出给JavaScript写入内存空间函数void writeToArray(int* arr, int index, int value) {arr[index] value;} // 将导出给JavaScript快排函数int* qSort(int* arr, int length) { std::sort(arr, arr length);return arr;}// 将导出给JavaScript斐波那契数列函数int fib (int n) {if (n 0) return 0;if (n 2) return 1;return fib(n - 2) fib(n - 1);}
}int main () {}2.2.2 JavaScript部分 读取WebAssembly文件 读取WebAssembly文件方法有很多经过若干版本迭代使用MDN最新推荐的方法 WebAssembly.instantiateStreaming(fetch(fileName), importObject)读取 传入C/C模块初始值 类似node运行时可以传参 node build.js --envdevelopment一样C/C编译后的wasm模块也需要传参。传参的标准可以参考WASI专门为WebAssembly设计的规范。传参通过读取wasm模块的第二个参数传递是否传参由wasm模块决定。 由下图圈出部分可知需要给wasm模块传递什么样的参数。 注直接打开wasm文件打不开都是二进制。可以通过浏览器查看对应的浏览器层面的汇编语言。 注下面的传参很简单。如果在C/C引入了更多的模块例如 #incldueiostream需要传入更多初始参数。 传递引用到wasm模块 下述代码在调用wasm的 qSort时不能直接把一个JavaScript数组传递过去这样会导致C/C的快排函数读取失败。传递引用时需要有C/C编程思想 传递指针 首先肯定要传递指针指针的值实际是地址所以需要传数值。申请空间 需要在wasm模块中为函数形参申请内存空间并将需要排序的数组写入。 读取引用从wasm模块 读取引用类型和传递引用类型类似都要以指针为中心。 读取指针 qSort函数返回指针其实就是数值需要我们从wasm模块的内存中读取对应地址内容。转换为JavaScript对象 转换为JavaScript对象一般利用 Buffer类实现下面文件接收 int数组因此使用 Int32Array类转化为JavaScript对象。 htmlheadmeta charsetutf-8 //headbodyscript// 初始化随机数据const handleInitData (length) {return Array.from({ length }).map(() Math.floor(Math.random() * length));};// 加载WebAssembly文件const handleUseWebAssembly (fileName) {// C运行时传入的参数具体传入什么变量需要等wasm生成后再分析。const importObject {wasi_snapshot_preview1: {proc_exit: function (code) {console.log(Process exited with code ${code});},},};// 利用fetch加载wasm文件return WebAssembly.instantiateStreaming(fetch(fileName), importObject);};// 把数据传给wasm模块const handlePostData (result, initData) {// 获取C提供的函数const {// 在C所在的wasm中申请数组内存createIntArray,// 在C所在的wasm中向某个内存地址写入数据writeToArray,} result?.instance?.exports;const length initData.length;// 在wasm申请一片内存空间用于存储数组const arrPointer createIntArray(length);// 向刚刚申请的内存空间中写入数据Array.from({ length }).forEach((_, index) writeToArray(arrPointer, index, initData[index]));return arrPointer;};// 排序const handleSort (result, initData, dataPointer) {const length initData.length;const startJS performance.now();// sort默认转成字符串排序需要转回数值再排序initData.sort((a, b) Number(a) - Number(b));const endJS performance.now();console.log(JS排序${length}条数据用时${(endJS - startJS) / 1000}秒);const { qSort } result?.instance?.exports;const startC performance.now();const newPointer qSort(dataPointer, length);const endC performance.now();console.log(C排序${length}条数据用时${(endC - startC) / 1000}秒);return newPointer;};// 输出排序结果const handlePrint (result, length, pointer, jsResult) {const data new Int32Array(// Buffer对象表示获取WebAssembly文件使用的内存空间result.instance.exports.memory.buffer,pointer,length);const cResult Array.from(data);console.log(JavaScript排序结果是, jsResult);console.log(C排序结果是, cResult);};(async () {// 初始化10万条随机数用于排序const length 1e6;// 要导入的WebAssembly文件const fileName ./test-emcc.wasm;// 初始化数据const initData handleInitData(length);// 读取WebAssembly文件const result await handleUseWebAssembly(fileName);// 把初始化数据传给WebAssembly文件const dataPointer handlePostData(result, initData);// 排序const newPointer handleSort(result, initData, dataPointer);// 输出排序结果handlePrint(result, initData.length, newPointer, initData);})();/script/body
/html2.2.3 Web服务器部分 上面直接引入wasm文件会有同源限制问题。下面用原生node实现一个简单的web服务器解决该问题。 let fs require(fs);
function read(path, res) {
fs.readFile(path, function (err, data) {if (err) console.log(err);else if (path.slice(-2, path.length) js) {res.writeHead(200, {Content-Type: text/javascript,});res.write(data);res.end();} else if (path.slice(-4, path.length) html) {res.writeHead(200, {Content-Type: text/html,});res.write(data);res.end();} else if (path.slice(-4, path.length) wasm) {res.writeHead(200, {Content-Type: application/wasm,});res.write(data);res.end();}
});
}
require(http)
.createServer(function (req, res) {if (req.url /favicon.ico) res.end();else read(. req.url, res);
})
.listen(3000, function (err) {if (err) console.log(err);else console.log(运行成功);
}); 2.3 计算结果 实验结果阐述 输出结果表示wasm模块执行效率要比JavaScript效率高了一倍以上但是这只是一个简单的使用。网上有其它实验表示平均基于C/C的wasm模块的效率要比JavaScript高30%~50%但wasm相比C/C直接编译后再生成exe文件在windows上运行效率低30%。 实验结果概述 运行速度JavaScript 基于C/C的wasm模块 原生环境的C/C 2.4 特点分析 效率高 虽然没有让性能成倍提升但是提升30%~50%的性能还可以让人接受。 编译过程参考少 C/C编译成wasm时发现Emscripten的文档很老并且网上参考博客也很古老参考内容不多出错不好排查。 需要前端直面指针和内存 相互交换引用类型时使用JavaScript不得不直面指针和内存操作。和JavaScript设计初衷不符。 3.优化Tensorflow
3.1 优化流程概述 流程背景 为了缓解服务器压力需要将某些模块的人脸识别功能迁移到前端完成。目前使用了基于tensorflow的 face-api相关库和模型实现考虑使用多线程和wasm做进一步优化。 流程概述 还没有分析和实现完暂时用 face-api的测试仓库举例。 注意事项 跨环境对比 face-api中只提供了node环境的wasm模块对于浏览器环境没有给出wasm模块。因此只用node下的wasm模块和浏览器的普通模块做对比。不在node环境下对比 不用node环境作对比是因为需要安装的包太麻烦里面的tensorflow并不是全部由JavaScript实现还需要安装精确版本的python和C/C的编译器。对比存在差异 face-api提供的node下的wasm版本并不支持使用GPU加速但是浏览器环境下支持自动使用GPU加速。因此对比时会考虑到GPU加速带来的影响。 3.2 优化流程详解
3.2.1 浏览器部分 基于demo中的index.js进行修改下面只是截取了修改的部分。 注计算时间时考虑YOLO目标检测和face-api人脸识别两个神经网络的时间。 for (const img of samples) {document.body.appendChild(document.createElement(br));const canvas await image(img);try {const start performance.now();const dataTinyYolo await faceapi.detectAllFaces(canvas, optionsTinyFace).withFaceLandmarks().withFaceExpressions().withFaceDescriptors().withAgeAndGender();const dataSSDMobileNet await faceapi.detectAllFaces(canvas, optionsSSDMobileNet).withFaceLandmarks().withFaceExpressions().withFaceDescriptors().withAgeAndGender();const end performance.now();const time (end - start) / 1000;timeList.push(time);console.log(图片${timeList.length}耗时${time}秒);} catch (err) {log(Image: ${img} Error during processing ${str(err)});}
}console.log(平均耗时${timeList.reduce((sum, time) time sum, 0) / timeList.length}秒
);3.2.2 Node部分 基于demo中的node-wasm.js进行修改。修改内容较多下述代码给出了详细的注释。 注计算时间时由于没有YOLO目标检测这里只计算face-api识别人脸的时间。 const fs require(fs);
const image require(canvas/image);
const tf require(tensorflow/tfjs);
const wasm require(tensorflow/tfjs-backend-wasm);
const faceapi require(../dist/face-api.node-wasm.js);async function readImage(imageFile) {
const buffer fs.readFileSync(imageFile);
const canvas await image.imageFromBuffer(buffer);
const imageData image.getImageData(canvas);// 图片转化成tensor向量
const tensor tf.tidy(() {const data tf.tensor(Array.from(imageData?.data || []),[canvas.height, canvas.width, 4],int32);const channels tf.split(data, 4, 2);const rgb tf.stack([channels[0], channels[1], channels[2]], 2);const squeeze tf.squeeze(rgb);return squeeze;
});
return tensor;
}async function main() {
// 加载wasm形式的tensorflow
wasm.setWasmPaths(// 国内jsdelivr镜像https://jsd.cdn.zzko.cn/npm/tensorflow/tfjs-backend-wasm/dist/,true
);
await tf.setBackend(wasm);
await tf.ready();console.log(FaceAPI版本 ${faceapi.version});
console.log(TensorFlow版本 ${tf.version_core});
console.log(TensorFlow模式 ${faceapi.tf.getBackend()});// 加载SSD Mobilenet V1神经网络判断所有面部
await faceapi.nets.ssdMobilenetv1.loadFromDisk(model);
// 加载68点阵判断面部神经网络
await faceapi.nets.faceLandmark68Net.loadFromDisk(model);
// 加载年龄和性别神经网络
await faceapi.nets.ageGenderNet.loadFromDisk(model);
// 加载人的脸判断神经网络
await faceapi.nets.faceRecognitionNet.loadFromDisk(model);
// 加载标签神经网络
await faceapi.nets.faceExpressionNet.loadFromDisk(model);// 配置第一个网络SSD神经网络网络的参数其它神经网络用默认参数
const options new faceapi.SsdMobilenetv1Options({minConfidence: 0.1,maxResults: 10,
});// 待检测图片列表
const ImageList Array.from({ length: 6 });
const getImagePath (index) demo/sample${index}.jpg;// 依次检测图片测试发现下面faceapi并行调用会阻塞
const detectList ImageList.reduce(async (previousPromise, _, index) {const timeList await previousPromise;const tensor await readImage(getImagePath(index 1));const start performance.now();// 调用神经网络进行识别await faceapi.detectAllFaces(tensor, options).withFaceLandmarks().withFaceExpressions().withFaceDescriptors().withAgeAndGender();const end performance.now();const elapsedTime (end - start) / 1000;timeList.push(elapsedTime);console.log(图片${index 1}耗时${elapsedTime}秒);// 销毁向量tf.dispose(tensor);return Promise.resolve(timeList);
}, Promise.resolve([]));detectList.then((list) {const averageTime list.reduce((sum, time) sum time, 0) / list.length;console.log(平均时间是${averageTime}秒);
});
}main();3.3 优化结果 结论 不使用GPU加速的tensorflow的wasm版本的速度逼近使用GPU加速的tensorflow的普通JavaScript版本。可以看出wasm还是有明显加速效果的。 浏览器部分 使用GPU加速tensorflow。去除第一个极端例子后最终平均时间在1秒以内集成显卡使用率有明显波动。 Node部分 使用wasm加速tensorflow。最终平均时间是1秒出头两个GPU的使用率没有明显波动 4.优化多线程
4.1 优化举例 哔哩哔哩的投稿页面可以看到有两个运用wasm的地方第一个是直接提供计算密集型的操作函数。第二个是工作线程可以看出是在tensorflow的工作线程中又引入了wasm提速主要是用于快速生成AI视频封面。 4.2 优化线程池举例 例子后续再写
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/87957.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!