Erlang中atom的實現

2022-04-01 23:04:54 字數 2337 閱讀 8216

erlang的原子(atom)在匹配中有著重要作用,它兼顧了可讀性和執行效率。 通過atom,可以實現很多靈活高效的應用。

atom可以看作是給字串生成了乙個id,內部使用的是id值,必要時可以取出它的內容(字串),例如用於列印輸出。

atom 的 eterm 除去 6 位的標籤之外剩下的部分,就是 atom 在 erlang 虛擬機器中的索引,也就是乙個整數值。在 erlang 中,有關 atom 比較的操作只需要比較兩個索引值即可,就是整數操作,因此非常高效。atom 本身是乙個字串,那麼 atom 的索引是怎樣對應上具體的字串的呢?也就是需要實現字串和索引值之間的互相對映,字串和索引值都必須唯一,這顯然需要使用雜湊表。erlang 虛擬機器內實現了一套通用的索引和雜湊表機制,atom 表就是這個機制的乙個客戶。下圖是這套機制中關鍵資料結構之間的關係。

圖中左側是雜湊表部分,右側是索引部分。先看左側。這個雜湊表採用的是標準的資料結構教科書上的實現。查詢的時候:通過雜湊函式計算被雜湊物件的雜湊值,然後對雜湊表的長度取模,得到圖中左側指標陣列的索引,接下來運氣好的話能直接得到查詢的物件(封裝在 hashbucket 中),運氣不好的話可能查不到,或者發生碰撞進行線性搜尋(例如圖中通過雜湊值得到索引 2 的時候就發生了碰撞,需要線性搜尋 hashbucket 中匹配的 hvalue)。插入的時候:同樣是先計算雜湊值得到索引,然後看對應的指標是否已經有物件了,如果沒有,則直接加入,如果有的話,則插入佇列頭部。雜湊表在擴容的時候,會選擇下乙個合適的大小(erts/emulator/beam/hash.c 檔案中的 h_size_table 陣列列出了雜湊表大小增長的序列,陣列裡面都是素數,但是基本上符合倍增的關係),把老表複製到新錶,然後刪除老表。當然,增長是有限制的,雜湊表大小不能超出 h_size_table 陣列中指定的最大值。

圖中右側是索引部分。索引表實際上是指向被索引物件的指標的陣列,被索引物件的索引值就是對應指標在陣列中的自然順序。由於事先無法確定具體的索引數目,所以索引表的大小是動態增長的,增長單位為乙個索引塊的大小,每個索引塊中有固定數目的指標(例如 1024 個)。雜湊表中每插入乙個新的物件的時候,設定索引表中最小的那個可用索引。如果新的索引超出了索引塊的邊界,那麼分配乙個新的索引塊,並且更新索引塊表中的指標。同樣,索引表的增長也是有限度的,索引塊表的指標用完了就不能再增長了。索引塊表的長度是在建立索引表的時候設定的,所以理論上可以很大,不超出記憶體限制即可,但是實際中還要考慮雜湊表的大小,這兩者是相互制約的。

描述了雜湊和索引的資料結構和實現之後,我們回到雜湊索引的客戶——atom。由於雜湊和索引是通用的,所以雜湊表指向的物件是 hashbucket 資料結構,而索引表指向的是 indexslot 資料結構。為了將雜湊和索引結合起來,這兩個資料結構是重疊的,hashbucket 在 indexslot 頭部。具體客戶在使用的時候,要把 indexslot 放在自己的頭部,這樣就把具體的物件和雜湊索引結合起來了(就好像原始的物件導向的實現)。 從圖中可以看出,我們的 atom 資料結構除了上述結構之外,還包含了具體的字串指標、長度以及編碼資訊。將這些資訊串起來之後,我們就可以高效地在常量時間內查詢 atom 是否已經存在,已經存在的 atom 的索引值是什麼,某個索引值對應的 atom 是什麼以及插入新的 atom。

另乙個問題,向雜湊表插入元素的時候,雜湊表要負責分配物件的記憶體,而雜湊表是通用的,那麼雜湊表怎麼知道分配例如 atom 呢?解決方法是雜湊表中元素的分配、比較、釋放以及雜湊值計算的操作都通過**函式的方式提供給雜湊表。這裡 atom 使用的雜湊函式是經典的 hashpjw 雜湊演算法,這個演算法是字串雜湊常用的演算法。

在乙個 erlang 節點內,atom 表是全域性共享的,因此多個執行緒對 atom 表的訪問是通過讀寫鎖保護的。對 atom 表的操作絕大部分都是讀操作,只有真正插入新的 atom 時的操作才是寫操作,插入新 atom 的情況一般不頻繁,而且也很少有多個執行緒爭搶著插入新 atom 的情況,大部分情況都是試圖插入 atom 但是發現其實已經存在了,因此 atom 表使用的讀寫鎖是針對讀操作優化的讀寫鎖。使用針對讀操作優化的讀寫鎖時讀鎖的開銷非常小,即使是在大量執行緒爭用的情況下。

erlang 中的 atom 表是不進行垃圾**的,畢竟在程式設計師不濫用 atom 的情況下,atom 數目可以控制在合理範圍內。而且跟蹤每乙個 atom 的引用狀況會產生很大的開銷。所以不要濫用 atom,把 atom 表塞滿是把 erlang 虛擬機器 crash 掉的一種方法。目前預設的 atom 數目限制是 1048576(1024

×1024

),通過虛擬機器的 +t 引數可以設定。

atom的實現檔案位於erts/emulator/beam/atom.h atom.c  index.h index.c hash.h hash.c

本文內容**:

Atom飛行手冊翻譯 2 12 在Atom中寫作

雖然atom通常可能用來編寫軟體的 但是它還可以用來高效地編寫文章。這通常採用一些標記語言,比如說markdown和asciidoc 也就是英文手冊所用的格式 來完成。下面我們會很快瀏覽一遍atom提供給你用來寫文章的一些工具。如果你在處理文字 通常包括純文字檔案,github markdown檔案...

使用erlang實現的quicksort

最近erlang開始變得流行起來,一下是乙個erlang中的quicksort的 author ztl created nov 26,2008 description todo add description to mylib module mylib include files exported ...

erlang中的spawn函式

spawn fun pid 引數型別 fun function 引數為空的函式 返回型別 程序pid 說明 生成乙個由fun函式啟動的 引數為空的新程序,並返回程序的pid。spawn node,fun pid 引數型別 node node 節點 fun function 引數為空的函式 返回型別 ...