「譯」圖解 ArrayBuffers 和 SharedArrayBuffers

做者:Lin Clark
譯者:Cody Chan
原帖連接:A cartoon intro to ArrayBuffers and SharedArrayBuffers

這是圖解 SharedArrayBuffers 系列的第二篇:web

  1. 內存管理碰撞課程segmentfault

  2. 圖解 ArrayBuffers 和 SharedArrayBuffers數組

  3. 用 Atomics 避免 SharedArrayBuffers 競爭條件瀏覽器

上一篇文章中,我解釋了 JavaScript 這類自動管理內存的語言是如何處理內存的,一樣也解釋了相似 C 語言這種手動管理內存的語言安全

爲何這對於咱們討論的 ArrayBuffersSharedArrayBuffers 如此重要?多線程

由於即便你使用的是 JavaScript 這種自動管理內存的語言,ArrayBuffers 也提供了一種手動處理數據的途徑併發

爲何你會有這樣的需求呢?工具

正如上篇文章所說,這裏有個權衡,自動管理內存對開發者是友好的,可是這會增長機器負擔,甚至會有性能問題post

例如,JS 裏建立一個變量,引擎會去猜想變量的類型以及內存裏如何表示。由於有了類型猜想,JS 引擎一般會比真實須要預留更多的空間。根據變量不一樣,內存分配可能會是真實需求的 2-8 倍,這致使了內存浪費性能

並且,某些建立和使用 JS 對象的場景會讓垃圾回收變得很困難。若是你是手動維護的內存,能夠根據實際使用需求來決定分配和釋放內存的策略

不少時候,這不是什麼大不了的事。大多數場景並不會對性能要求那麼苛刻,反而更多地擔憂管理內存的麻煩。並且通常狀況下,手動管理內存可能更慢

可是對於底層須要極致優化的場景,ArrayBuffers 和 SharedArrayBuffers 爲你提供了可能

ArrayBuffer 是如何工做的

ArrayBuffer 跟其它 JavaScript 數組差很少,可是不是全部 JavaScript 類型均可以放進去,好比對象、字符串。你惟一能夠放進去的只有字節(能夠用數字表示)

須要澄清的一點是,你事實上不是直接把這個字節到 ArrayBuffer 裏就好了,ArrayBuffer 並不知道字節有多長,該用多少位去存

ArrayBuffer 僅僅是一個個 0/1 組成的串,它不知道第一個元素和第二個元素的分割點

爲了提供必要的上下文信息,把 ArrayBuffer 分塊,咱們須要把它包裹到視圖裏,這些數據的視圖能夠經過帶類型的數組添加,已經支持不少種類型的數組了

例如,你能夠用一個 Int8 類型的數組把 0/1 串分割成 8 位一組的序列

或者你能夠用一個無符的 Int16 類型數組,把它分割成 16 位一組的序列,能夠把它看成無符整型處理

甚至你能夠在同一個基礎 buffer 上同時處理多種視圖,不一樣視圖在相同操做下會返回不一樣的結果

例如,若是咱們從某個 ArrayBuffer 的 Int8 視圖獲得第 0 和第 1 個元素的值,在 Uint16 視圖下,第 0 個元素與其有相同二進制位值,可是獲得的值也會不同

這種方式下,ArrayBuffer 幾乎是扮演原始內存角色了,它模擬內存的各類跟 C 語言裏相似的操做

你可能納悶了,爲何不讓開發者直接操縱內存而是採用這個抽象層。由於直接操做內存會有安全風險,這個之後的文章會講

什麼是 SharedArrayBuffer

爲了說明白 SharedArrayBuffers,我須要稍微解釋下並行運行代碼和 JavaScript 的關係

爲了更快運行代碼或者更更快響應用戶事件,你可能會讓代碼並行運行,爲了作到這點,你須要分割工做

一個典型的應用中,全部的工做都由一個單獨的主線程處理,這點我以前提到過……這個主線程就像一個全棧工程師,掌管着 JavaScript、DOM 和 視圖

任何可以從主線程負載減小工做的方法都對代碼運行效率有幫助,某些狀況下,ArrayBuffers 能夠減小大量應該由主線程作的工做

可是也有些時候減小主線程負載是遠遠不夠的,有時你須要增援,你須要分割你的任務

大多數語言裏,這種分割工做的方法可使用多線程實現,這就像不少人同時在一個項目裏工做。若是你能夠完美地把任務分割爲多個獨立的部分,你能夠分給不一樣的線程,而後,這些線程就同時各類獨立執行這些任務

在 JavaScript 裏,你能夠藉助 web worker 作這種事,這些 web workers 跟其它語言的線程仍是有些區別的,默認它們不能共享內存

這意味着若是你想分配你的任務給別的線程,你須要完整把任務複製過去,這能夠經過 postMessage 實現

postMessage 把你傳給它的任何對象都序列化,發送到其它 web worker,而後那邊接收後反序列化並放進內存

這個過程是很是慢的

某些類型數據(如 ArrayBuffers)你能夠經過移動內存的方式實現,這意味着把某個特定區域的內存移過去後其它 web worker 就能夠直接訪問了

可是,以前的 web worker 就沒法訪問了

對於某些場景這是實用的,可是也有不少場景對性能要求高,你只能使用共享的內存

而這就是 SharedArrayBuffers 爲你提供的

有了 SharedArrayBuffer 後,多個 web worker 就能夠同時讀寫同一塊內存了

你不再須要 postMessage 伴有時延的通訊了,多個 web worker 對數據訪問都沒有時延了

固然,這種同時訪問也有風險,會產生競爭條件

這個下一篇文章會細說

SharedArrayBuffers 支持狀況

全部主流瀏覽器都將會支持 SharedArrayBuffers

Safari 10.1 已經支持了,Firefox 和 Chrome 也會很快支持併發布,Edge 會在他們秋季 Windows 更新的時候發佈

即便全部主流瀏覽器都支持了,咱們也不但願開發者直接使用它們,事實上,咱們是反對的。你應該只使用更高級的封裝好的抽象層接口

咱們期盼的是 JavaScript 庫開發者能夠提供更簡單安全的方法來使用 SharedArrayBuffers

並且,一旦 SharedArrayBuffers 內置到平臺中,WebAssembly 能夠經過它實現多線程,到那時候你就可使用相似 Rust 的多線程語言輕鬆玩轉多線程了

下一篇文章咱們會介紹一個爲避免競爭條件的庫提供基礎操做的工具(Atomics

相關文章
相關標籤/搜索