摘要:知乎上也有相關的討論,開發(fā)的下一代編輯器莫非已經定義為上一代編輯器了嗎。
這篇是我在知乎的回答,原文在這里:justjavac: VS Code、ATOM這些開源文本編輯器的代碼實現中有哪些奇技淫巧?
研究 V8 比較多,也關注了一下 vscode 和 atom 的性能,每次 vscode、atom 的 change log 我都會看一遍。印象最深的是 vscode 1.14 的一次更新日志,doApplyEdits Lines inserted using splice · Issue #351 · Microsoft/monaco-editor:不要在循環(huán)中使用 splice。
下圖是我一年前跑的測試結果:Inserting an array within an array
300+倍的差距。
在之前 vscode 還有一次很大的性能提升,在版本 1.9 的時候,改進了語法高亮的算法。
語法高亮的過程通常分為 2 個階段(tokenization 和 render):先將源碼分割為 token,然后使用不同的主題對分割后的 token 進行著色。
tokenization 的過程是:從上到下逐行運行。tokenizer 在行的末尾存儲一些狀態(tài),在 tokenize 下一行時會用到這些狀態(tài)。這樣,在用戶進行編輯時僅需要重新 tokenize 行的一小部分,而不需要掃描整個文件內容。
還有一種情況是當前行的輸入會影響到后面(甚至是前面)的行,這時會用到結束狀態(tài):
在 1.9 之前的版本,vscode 如何 tokenization 呢?
比如上面的代碼:
在 vscode 種這樣存儲:
tokens = [ { startIndex: 0, type: "keyword.js" }, { startIndex: 8, type: "" }, { startIndex: 9, type: "identifier.js" }, { startIndex: 11, type: "delimiter.paren.js" }, { startIndex: 12, type: "delimiter.paren.js" }, { startIndex: 13, type: "" }, { startIndex: 14, type: "delimiter.curly.js" }, ]
{ startIndex: 0, type: "keyword.js" } 表示從 0 開始的 token 是一個 keyword。
VSCode 團隊在博客種指出這在 Chrome 中占據 648 個字節(jié),因此存儲這樣的對象在內存方面的代價非常高(每個對象實例必須保留指向其原型的空間,以及其屬性列表等)。為 15 個字符存儲 648 字節(jié)是不可接受的。
所以,vscode 使用二進制來存儲token:
// 0 1 2 3 4 map = ["", "keyword.js", "identifier.js", "delimiter.paren.js", "delimiter.curly.js"]; tokens = [ { startIndex: 0, type: 1 }, { startIndex: 8, type: 0 }, { startIndex: 9, type: 2 }, { startIndex: 11, type: 3 }, { startIndex: 12, type: 3 }, { startIndex: 13, type: 0 }, { startIndex: 14, type: 4 }, ]
和上面的表示法相比,只是把 type 由字符串變成了數字,本質上并沒有節(jié)約太多的內存。但是別著急,vscode 還有黑科技。
我們都知道 JavaScript 使用 IEEE-754 標準存儲雙精度浮點數,尾數為 53bit。能夠在不丟失精度的情況下處理的最大整數為 2^53-1。因此 vscode 使用其中的 48big 進行編碼:使用 32bit 來存儲 startIndex,16bit 來存儲type。 于是上面的對象在 vscode 種被存儲為:
tokens = [ // type startIndex 4294967296, // 0000000000000001 00000000000000000000000000000000 8, // 0000000000000000 00000000000000000000000000001000 8589934601, // 0000000000000010 00000000000000000000000000001001 12884901899, // 0000000000000011 00000000000000000000000000001011 12884901900, // 0000000000000011 00000000000000000000000000001100 13, // 0000000000000000 00000000000000000000000000001101 17179869198, // 0000000000000100 00000000000000000000000000001110 ]
每個數字是 64bit(8字節(jié)),一共是 7 個數字,存儲這些元素一共需要 7*8 = 56 字節(jié),再加上數組的額外開銷共需要 104 個字節(jié),只有之前的 648 字節(jié)的 1/6。
而主題的渲染則用到了 Trie 數據結構。
這個學過《數據結構》的都懂,算不上奇技淫巧,就不展開了。
這一切都是 2017 年 3 月發(fā)布的 vscode 1.9。
而今年 3 月,vscode 又重寫了 Text Buffer。用戶使用編輯器,大部分時間就是寫新代碼,改舊代碼,說到底還是對 text 進行編輯。
對于高性能的文本操作,vscode 最初嘗試使用 C++ 進行編寫,畢竟 C++ 的性能要比 JavaScript 高出不少,但是事實卻不夠理想,使用 C++ 確實節(jié)約了內存,但是在使用 C++ 模塊時,需要在 JavaScript 和 C++ 之間往返數次,這大大減慢了 vscode 的性能。
vscode 團隊從 Vyacheslav Egorov 的一篇文章 Maybe you don"t need Rust and WASM to speed up your JS 收到了啟發(fā),如何充分壓榨 V8 引擎的性能。mrale.ph 的博客我?guī)缀趺科伎?,非常經典,也非常難懂 。
大多編輯器都是基于行的。程序員逐行編寫代碼,編譯器提供基于行的反饋信息,堆棧跟蹤包含行號,tokenization 引擎逐行運行…… 在 vscode 的早期版本中也是直接把每行代碼作為字符串存儲在數組中。
但是這種方式存在一些問題:
無法打開大文件,因為把所有內容讀入數組中可能導致內存不足。
即使文件不大,但是行數太多也無法打開。例如,一個用戶無法打開一個 35 MB 的文件。根本原因是該文件的行數太多,1370 萬行。引擎將為ModelLine每行和每個對象使用大約 40-60 個字節(jié),因此整個數組使用大約 600MB 內存來存儲文檔。也就是說打開這個 35M 的文件需要 600M 的內容,20 倍啊?。?!
另一個問題就是速度。為了構建這個數組,必須通過換行符分割內容,以便每行獲得一個字符串對象。
于是 vscode 開始尋找新的數據結果,最終選擇了 Piece table。不知道為什么這么晚才選擇 piece table,要知道在微軟的 office word 中早就已經使用了 piece table。我也是在一次 Java 讀取 word 的 jar 包源碼中第一次知道的 piece table 數據結構。
推薦幾篇延伸閱讀的文章:
Emacs 編輯器的 buffer 論文:Flexichain: An editable sequence and its gap-buffer implementation 2004-04-05
piece table 的:Data Structures for Text Sequences 1998-06-10
Ropes: An Alternative to Strings 1995-12
目前主要的三種編輯方式有 gap buffer, rope, piece table。
最近用 Atom 少了。
上一次讓我興奮的地方是:The State of Atom"s Performance。在2017年6月 Atom 使用了 piece table 數據結構,使用 C++ 重新實現了 text buffer:Atom"s new concurrency-friendly buffer implementation。比 vscode 還要早半年,但是為什么還是這么慢呢???
Atom 使用 V8 的自定義快照(snapshot)提升啟動性能,最終刪除了影響性能的 jQuery 和自定義 element。就連 V8 的
Atom 還更新了 DOM 渲染的方式:A new approach to text rendering,而這個新算法包括一個類似 React 的 vdom,從 issue 來看這是一個大工程啊,包含了近 100 個 task
經過一系列優(yōu)化,官方說道:
we made loading Atom almost 50% faster and snapshots were a crucial tool that enabled some otherwise impossible optimizations.
我們使 Atom 快了 50%,snapshot 功不可沒。(PS:我一定是使用了假的 Atom)
不過 snapshot 確實是 V8 的神器,Nodejs 也看到了 Atom 的成果,于 2017-11-16 開了 issue :speeding up Node.js startup using V8 snapshot · Issue #17058 · nodejs/node。這在我之前的專欄里面有介紹:Node.js 新計劃:使用 V8 snapshot 將啟動速度提升 8 倍。
最近一次關注 Atom 是 atom/xray。知乎上也有相關的討論,atom 開發(fā)的下一代編輯器(莫非已經定義 atom 為上一代編輯器了嗎)。大概就是一種“大號廢了,開小號重練”的感覺。
值得學習的地方是 text 處理使用 copy-on-write CRDT:
如果一直關注 Atom,對于 CRDT 應該不會陌生。Atom 的多人實時共同編輯插件 https://teletype.atom.io/ 就是使用的 CRDT。
CRDT 全稱:Conflict-Free Replicated Data Types,強行翻譯過來就是“無沖突可復制數據類型”。
CRDT 論文: A comprehensive study of Convergent and Commutative Replicated Data Types 2011-01-13
CAP定理:在分布式系統(tǒng)中,最多只能同時滿足一致性(Consistency)、可用性(Availability)和分區(qū)容錯性(Partition tolerance)這三項中的兩項。
很多分布式系統(tǒng)都舍棄了C(一致性):允許可以在某些時刻不一致,轉而求其次要求系統(tǒng)滿足最終一致性。這也是目前很多 nosql 數據庫追求的方式(另一種是傳統(tǒng)的符合 ACID 特性的數據庫系統(tǒng),放棄了A(可用性),這種系統(tǒng)稱為強一致性)。
而在最終一致性分布式系統(tǒng)中,一個最基本的問題就是,應該采用什么樣的數據結構來保證最終一致性? 答案就是 CRDT。
atom/teletype-crdt
這篇文章只是一個提綱,里面的每個知識點都可以展開了講上三天三夜。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://systransis.cn/yun/94535.html
摘要:如果你問一個年輕的前端開發(fā)人員,你在今后的年內如何提升自己的能力他可能會說我現在對前端比較熟悉,但我想深入了解,另外現在發(fā)展的很快我也想看一下。再舉一個例子,我會留意身邊的程序員所用的鍵盤。只有少部分的程序員會買高端的靜電容鍵盤,比如。 如果你問一個年輕的前端開發(fā)人員,你在今后的 3 年內如何提升自己的能力?他可能會說我現在對 Web 前端比較熟悉,但我想深入了解 AngularJS,...
摘要:是一款免費但優(yōu)秀的代碼編輯器,運行在環(huán)境下,可以支持多種編程語言。是免費開源的文本和代碼編輯器,它是運行在上,底層依賴的架構是的開源項目。 代碼編輯器對于程序員來說十分重要,一個好的編輯器可以節(jié)省開發(fā)時間,提高工作效率。這篇文章會介紹10個優(yōu)秀且免費的編輯器,它們都是非常方便易用的環(huán)境,你可以用它們來編寫代碼,查看源文件和文檔等,簡化你的工作。 代碼編輯器對于程序員來說十分重要,一...
摘要:是一款免費但優(yōu)秀的代碼編輯器,運行在環(huán)境下,可以支持多種編程語言。是免費開源的文本和代碼編輯器,它是運行在上,底層依賴的架構是的開源項目。 代碼編輯器對于程序員來說十分重要,一個好的編輯器可以節(jié)省開發(fā)時間,提高工作效率。這篇文章會介紹10個優(yōu)秀且免費的編輯器,它們都是非常方便易用的環(huán)境,你可以用它們來編寫代碼,查看源文件和文檔等,簡化你的工作。 代碼編輯器對于程序員來說十分重要,一...
摘要:軟件跨平臺支持以及,運行流暢,可謂是微軟的良心之作微軟有這個宇宙最強,自然也不會弱宇宙最強編輯器說到代碼編輯器,我們有必要提一提還有。 原文鏈接:VS Code上手與超實用插件安利 工欲善其事必先利其器 Visual Studio Code (簡稱 VS Code / VSC) 是一款免費開源的現代化輕量級代碼編輯器,支持幾乎所有主流的開發(fā)語言的語法高亮、智能代碼補全、自定義熱鍵、括號...
摘要:首發(fā)于酷家樂前端博客標題是我以第一視角基于開發(fā)客戶端產品的體驗,我將在之后分一系列文章向有興趣的朋友一步一步介紹我是怎么從玩玩具的心態(tài)開始接觸到去開發(fā)客戶端產品,最后隨著業(yè)務和功能的復雜度提升再不斷地優(yōu)化客戶端。 首發(fā)于酷家樂前端博客 標題是我以第一視角基于 Electron 開發(fā)客戶端產品的體驗,我將在之后分一系列文章向有興趣的朋友一步一步介紹我是怎么從玩玩具的心態(tài)開始接觸 Ele...
閱讀 3550·2023-04-26 00:16
閱讀 1367·2021-11-25 09:43
閱讀 3836·2021-11-23 09:51
閱讀 2975·2021-09-24 09:55
閱讀 726·2021-09-22 15:45
閱讀 1402·2021-07-30 15:30
閱讀 3071·2019-08-30 14:04
閱讀 2253·2019-08-26 13:46