<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
在前面的文章當中我們討論的是 python3 當中早期的內嵌資料結構字典的實現,在本篇文章當中主要介紹在後續對於字典的記憶體優化。
在前面的文章當中我們介紹的字典的資料結構主要如下所示:
typedef struct { PyObject_HEAD Py_ssize_t ma_used; PyDictKeysObject *ma_keys; PyObject **ma_values; } PyDictObject; struct _dictkeysobject { Py_ssize_t dk_refcnt; Py_ssize_t dk_size; dict_lookup_func dk_lookup; Py_ssize_t dk_usable; PyDictKeyEntry dk_entries[1]; }; typedef struct { /* Cached hash code of me_key. */ Py_hash_t me_hash; PyObject *me_key; PyObject *me_value; /* This field is only meaningful for combined tables */ } PyDictKeyEntry;
用圖示的方式表示如下圖所示:
所有的鍵值對都儲存在 dk_entries 陣列當中,比如對於 "Hello" "World" 這個鍵值對儲存過程如下所示,如果 "Hello" 的雜湊值等於 8 ,那麼計算出來物件在 dk_entries 陣列當中的下標位 0 。
在前面的文章當中我們談到了,在 cpython 當中 dk_entries 陣列當中的一個物件佔用 24 位元組的記憶體空間,在 cpython 當中的負載因子是 23frac{2}{3}32 。而一個 entry 的大小是 24 個位元組,如果 dk_entries 的長度是 1024 的話,那麼大概有 1024 / 3 * 24 = 8K 的記憶體空間是浪費的。為了解決這個問題,在新版的 cpython 當中採取了一個策略用於減少記憶體的使用。具體的設計如下圖所示:
在新的字典當中 cpython 對於 dk_entries 來說如果正常的雜湊表的長度為 8 的話,因為負載因子是 23frac{2}{3}32 真正給 dk_entries 分配的長度是 5 = 8 / 3,那麼現在有一個問題就是如何根據不同的雜湊值進行物件的儲存。dk_indices 就是這個作用的,他的長度和真正的雜湊表的長度是一樣的,dk_indices 是一個整型陣列這個陣列儲存的是要儲存物件在 dk_entries 當中的下標,比如在上面的例子當中 dk_indices[7] = 0,就表示雜湊值求餘數之後的值等於 7,0 表示物件在 dk_entries 當中的下標。
現在我們再插入一個資料 "World" "Hello" 鍵值對,假設 "World" 的雜湊值等於 8,那麼對雜湊值求餘數之後等於 0 ,那麼 dk_indices[0] 就是儲存物件在 dk_entries 陣列當中的下標的,圖中對應的下標為 1 (因為 dk_entries 陣列當中的每個資料都要使用,因此直接遞增即可,下一個物件來的話就儲存在 dk_entries 陣列的第 3 個(下標為 2)位置)。
首先我們先來分析一下陣列 dk_indices 的資料型別,在 cpython 的內部實現當中並沒有一刀切的直接將這個陣列當中的資料型別設定成 int 型別。
dk_indices 陣列主要有以下幾個型別:
與這個相關的程式碼如下所示:
/* lookup indices. returns DKIX_EMPTY, DKIX_DUMMY, or ix >=0 */ static inline Py_ssize_t dictkeys_get_index(const PyDictKeysObject *keys, Py_ssize_t i) { Py_ssize_t s = DK_SIZE(keys); Py_ssize_t ix; if (s <= 0xff) { const int8_t *indices = (const int8_t*)(keys->dk_indices); ix = indices[i]; } else if (s <= 0xffff) { const int16_t *indices = (const int16_t*)(keys->dk_indices); ix = indices[i]; } #if SIZEOF_VOID_P > 4 else if (s > 0xffffffff) { const int64_t *indices = (const int64_t*)(keys->dk_indices); ix = indices[i]; } #endif else { const int32_t *indices = (const int32_t*)(keys->dk_indices); ix = indices[i]; } assert(ix >= DKIX_DUMMY); return ix; }
現在來分析一下相關的記憶體使用情況:
雜湊表長度 | 能夠儲存的鍵值對數目 | 老版本 | 新版本 | 節約記憶體量(位元組) |
---|---|---|---|---|
256 | 256 * 2 / 3 = 170 | 24 * 256 = 6144 | 1 * 256 + 24 * 170 = 4336 | 1808 |
65536 | 65536 * 2 / 3 = 43690 | 24 * 65536 = 1572864 | 2 * 65536 + 24 * 43690 = 1179632 | 393232 |
從上面的表格我們可以看到雜湊表的長度越大我們節約的記憶體就越大,優化的效果就越明顯。
在本篇文章當中主要介紹了在 python3 當中對於字典的優化操作,主要是通過一個記憶體佔用量比較小的陣列去儲存鍵值對在真實儲存鍵值對當中的下標實現的,這個方法對於節約記憶體的效果是非常明顯的。
本篇文章是深入理解 python 虛擬機器器系列文章之一,
更多精彩內容合集可存取專案:github.com/Chang-LeHun…
以上就是Python 虛擬機器器字典dict的優化方法解析的詳細內容,更多關於Python 虛擬機器器字典dict優化的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45