web worker 的传值体式格局以及耗时对照

背景

前一阵子开辟的项目 pptx 导入, 由于本身的代码题目,引起了个机能题目,一个 40p 的 pptx 文件,转换成 json 数据,大提要耗时 60s+ ,虽然背面发明是某个运用频次异常高的函数内部,用了 new Function 组织函数 形成的(所以这里趁便提示一下,假如你很在意几毫秒的差异的话,发起郑重运用哈),然则在优化的过程当中,一度怀疑是机能达到了瓶颈,所以尝试了运用 web worker 去优化,由于是文件,平常内容都比较大,发明 web worker 在传值这块占用了大部分的时候,所以想开这篇来细致聊聊.

两种传值体式格局

关于 web worker 的基础用于以及传值体式格局,网上以及有一大堆引见了,这里就不赘述了,这里我们重点来看一下同一个文件用两种体式格局来传值,会有多大的差异,这边随便从电脑内里找了一个 96MB 的 PSD 文件来测试.

主线程

    fetch('./case.psd').then(file => {
            return file.blob();
        })

        .then(blob => {
            return new Promise(resolve => {
                let fileReader = new FileReader();
                fileReader.onload = e => {
                    resolve(e.target.result);
                }
                fileReader.readAsArrayBuffer(blob);
            })
        })

        .then(buf => {
            let worker = new Worker('1.js');

            console.time('盘算时候');
            worker.postMessage(buf);

            worker.onmessage = e => {
                console.timeEnd('盘算时候');
            }


        })

worker(子)线程, 这里为了防止不必要的要素滋扰,worker 线程内里什么也不做,在收到音讯后,直接 post 一个音讯归去

    self.onmessage = e => {
        postMessage(0);
    }

这边我直接用 FileReader 的 readAsArrayBuffer,读出来是一个长度为 96,138,230 的字符串,长度也许 0.96 亿, 耗时也许 70ms 摆布(同一个台电脑取 10 次平均值,下同)

我们轻微改一下上面主线程的代码,改用 转移数据 的体式格局

- worker.postMessage(buf);

+ worker.postMessage(buf, [buf]);

一样的数据, 耗时也许 17ms 摆布,这 17ms 好像是个固定值,我尝试换了个 800MB+ 的文件和一个内里啥都没有的空文本文件,也许都是这个时候.

差别的数据类型,用值通报的耗时也是不一样的

    fetch('./case.psd').then(file => {
            return file.blob();
        })

        .then(blob => {
            return new Promise(resolve => {
                let fileReader = new FileReader();
                fileReader.onload = e => {
                    resolve(e.target.result);
                }
                fileReader.readAsText(blob);
            })
        })

        .then(str => {
            console.log(str.length);
            let worker = new Worker('1.js');

            console.time('盘算时候');
            worker.postMessage(str);

            worker.onmessage = e => {
                console.timeEnd('盘算时候');
            }


        })

这里我们改用 FileReader 的 readAsText,读出来是一个长度为 95,855,954 的字符串,长度也许 0.95 亿, 耗时也许 118ms 摆布,一样我换了上面谁人内里啥都没有的空文本文件,耗时也是 17ms 摆布.

那我们试试用 readAsDataURL 看看读出来的数据要多久

    fetch('./case.psd').then(file => {
            return file.blob();
        })

        .then(blob => {
            return new Promise(resolve => {
                let fileReader = new FileReader();
                fileReader.onload = e => {
                    resolve(e.target.result);
                }
                fileReader.readAsDataURL(blob);
            })
        })

        .then(str => {
            console.log(str.length);
            let worker = new Worker('1.js');

            console.time('盘算时候');
            worker.postMessage(str);

            worker.onmessage = e => {
                console.timeEnd('盘算时候');
            }


        })

读出来是一个长度为 128,184,345 的字符串,长度也许 1,28 亿, 耗时也许 85ms 摆布(虽然字符串长度更长,然则耗时却更短)

以上耗时,均为主线成向 worker 线程单向通报数据的耗时.

结论

  1. 转移数据几乎是零开支(由于和通报空字符串的耗时是差不多的).
  2. 值通报的话,差别的数据类型,耗时也有差异,ArrayBuffer < base64 < 一般字符串.
  3. postMessage 通报音讯,除了发送数据的耗时外,另有其他开支(就是上面的 17ms). 固然每台电脑机能不一样,耗时也是不一样的,不过按比例来看,这个占比还挺大的.

关于转移的瑕玷, 网上也是有许多的, 这里也就不烦琐了, 总结一句就是数据没法同时在2个线程上运用.

别的个人以为假如是一般的数据,为了转移而去转换成 Transferable objects 的话, 大部分情况下是划不来的, 由于你需要在花在编码解码上的时候,会比直接通报花的时候多.

别的, 假如你是要用子线程处置惩罚图片的话, ImageBitmap 花样 合营近来新鲜出炉的 OffscreenCanvas 也许是不错的挑选.条件是你不需要斟酌兼容性题目.

末了是广告时候

我们40人的前端团队终年招兵买马中,在厦门的和想来厦门的童鞋们,不要怜惜你的简历,用力砸过来 邮箱:nuoya@gaoding.com, 期待你一起来稿事

原文地点 https://github.com/noahlam/ar…

    原文作者:noahlam
    原文地址: https://segmentfault.com/a/1190000018092681
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞