<dl id="opymh"></dl>

<div id="opymh"></div>
      <div id="opymh"><tr id="opymh"></tr></div>

        <em id="opymh"><ins id="opymh"><mark id="opymh"></mark></ins></em><sup id="opymh"><menu id="opymh"></menu></sup>

        <em id="opymh"></em>

        <em id="opymh"><ol id="opymh"></ol></em>

              頻道欄目
              首頁 > 程序開發 > web前端 > HTML/CSS > 正文
              webworker的傳值方式以及耗時對比
              2019-02-12 11:21:46           
              收藏   我要投稿

              背景

              前一陣子開發的項目 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 左右(雖然字符串長度更長,但是耗時卻更短)

              結論

              轉移數據幾乎是零開銷(因為和傳遞空字符串的耗時是差不多的). 值傳遞的話,不同的數據類型,耗時也有差別,ArrayBuffer < base64 < 普通字符串. postMessage 傳遞消息,除了發送數據的耗時外,還有其他開銷(就是上面的 17ms). 當然每臺電腦性能不一樣,耗時也是不一樣的,不過按比例來看,這個占比還挺大的.

              關于轉移的缺點, 網上也是有很多的, 這里也就不啰嗦了, 總結一句就是數據無法同時在2個線程上使用.

              另外個人覺得如果是普通的數據,為了轉移而去轉換成 Transferable objects 的話, 大部分情況下是劃不來的, 因為你需要在花在編碼解碼上的時間,會比直接傳遞花的時間多.

              另外, 如果你是要用子線程處理圖片的話, ImageBitmap 格式 配合最近新鮮出爐的 OffscreenCanvas 也許是不錯的選擇.前提是你不需要考慮兼容性問題.

              點擊復制鏈接 與好友分享!回本站首頁
              相關TAG標簽 webworker 傳值方式
              上一篇:關于Promise的9個提示
              下一篇:用JavaScript實現功能齊全的單鏈表
              相關文章
              圖文推薦
              點擊排行

              關于我們 | 聯系我們 | 廣告服務 | 投資合作 | 版權申明 | 在線幫助 | 網站地圖 | 作品發布 | Vip技術培訓 | 舉報中心

              版權所有: 紅黑聯盟--致力于做實用的IT技術學習網站

              极速飞艇好假
              <dl id="opymh"></dl>

              <div id="opymh"></div>
                  <div id="opymh"><tr id="opymh"></tr></div>

                    <em id="opymh"><ins id="opymh"><mark id="opymh"></mark></ins></em><sup id="opymh"><menu id="opymh"></menu></sup>

                    <em id="opymh"></em>

                    <em id="opymh"><ol id="opymh"></ol></em>

                          <dl id="opymh"></dl>

                          <div id="opymh"></div>
                              <div id="opymh"><tr id="opymh"></tr></div>

                                <em id="opymh"><ins id="opymh"><mark id="opymh"></mark></ins></em><sup id="opymh"><menu id="opymh"></menu></sup>

                                <em id="opymh"></em>

                                <em id="opymh"><ol id="opymh"></ol></em>