<
>

客户端JavaScript的线程池设计详解

2022-04-16 19:01:49 来源:易采站长站 作者:

目录
1.介绍:2.准备工作:3.测试spark-md5是否正常工作:4.线程池设计5.spark-md5对文件进行md5编码6.大量文件进行MD5加密并使用线程池优化总结

1.介绍:

本打算在客户端javascript进行机器学习算法计算时应用线程池来优化,就像()演示的神经网络。但是由于各种原因不了了之了。本次遇到了一个新的问题,客户端的MD5运算也是耗时操作,如果同时对多个字符串或文件进行MD5加密就可以使用线程池来优化。

2.准备工作:

到npm官网搜索spark-md5,到其github仓库下载spark-md5.js。该js文件支持AMD,CommonJS和web工作线程的模块系统,我们在实现线程池时,线程工作代码交给web工作线程处理。

; class MD5Pool { worker = [] status = "Idle" blockRequestQueue = [] constructor(size) { for(let i = 0; i < size; i ++) this.worker.push({ worker: new Worker("worker.js"), status: "Idle" }) } statusUpdate() { let sum = 0 this.worker.forEach(({ status }) => { if(status === "Busy") sum ++ }) if(sum === this.worker.length) this.status = "Busy" else this.status = "Idle" } assign() { if(this.status !== "Busy") { for (let i = 0; i < this.worker.length; i++) if (this.worker[i].status === "Idle") { this.worker[i].status = "Busy" this.statusUpdate() return { worker: this.worker[i].worker, index: i } } } else { let resolve = null let promise = new Promise(res => { resolve = res }) this.blockRequestQueue.push(resolve) return { info: "full", wait: promise } } } release(index) { this.worker[index].status = "Idle" // 阻塞请求队列中的第一个请求出队,队列中存储的是promise的resolve方法,此时执行,通知请求者已经有可用的线程了 if(this.blockRequestQueue.length) this.blockRequestQueue.shift()() this.status = "Idle" } } // input点击事件处理函数 function handleChanged() { let files = event.target.files // 创建一个大小为2的MD5计算线程池 let pool = new MD5Pool(2) // 计算切片文件的MD5编码 Array.prototype.forEach.call(files, file => { getMD5(file, pool) }) } // 获取文件的MD5编码的函数,第一个参数是文件,第二个参数是MD5线程池 async function getMD5(chunk, pool) { let thread = pool.assign() // 如果info为full,那么说明线程池线程已被全部占用,需要等待 if(thread.info === "full") { // 获取线程通知对象 let wait = thread.wait // 等到wait兑现时说明已经有可用的线程了 await wait thread = pool.assign() let { worker, index } = thread worker.postMessage(chunk) worker.onmessage = function (event) { console.log(event.data) pool.release(index) } } else { let { worker, index } = thread worker.postMessage(chunk) worker.onmessage = function (event) { console.log(event.data) pool.release(index) } } } </script></body>

工作线程代码

self.importScripts("spark-md5.js")let fd = new FileReader()let spark = new self.SparkMD5.ArrayBuffer()self.onmessage = function(event) {    // 获取文件    let chunk = event.data    // spark-md5要求计算文件的MD5必须切片计算    let chunks = fileSlice(chunk)    // 计算MD5编码    load(chunks)}// 切片函数function fileSlice(file) {    let pos = 0    let chunks = []    // 将文件平均切成10分计算MD5    const SLICE_SIZE = Math.ceil(file.size / 10)    while(pos < file.size) {        // slice可以自动处理第二个参数越界        chunks.push(file.slice(pos, pos + SLICE_SIZE))        pos += SLICE_SIZE    }    return chunks}// MD5计算函数async function load(chunks) {    for(let i = 0; i < chunks.length; i ++) {        fd.readAsArrayBuffer(chunks[i])        // 在这里希望节约空间,因此复用了FileReader,而不是每次循环新创建一个FileReader。需要等到FileReader完成read后才可以进行下一轮复用,因此用await阻塞。        await new Promise(res => {            fd.onload = function(event) {                spark.append(event.target.result)                if(i === chunks.length - 1) {                    self.postMessage(spark.end())                }                res()            }        })    }}

随机选取18个文件进行MD5编码,结果如下

在这里插入图片描述

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!

暂时禁止评论

微信扫一扫

易采站长站微信账号