Golang?Fasthttp選擇使用slice而非map?存儲(chǔ)請(qǐng)求數(shù)據(jù)原理探索
引言
Fasthttp 是一個(gè)高性能的 Golang HTTP 框架,它在設(shè)計(jì)上做了許多優(yōu)化以提高性能。其中一個(gè)顯著的設(shè)計(jì)選擇是使用 slice 而非 map 來(lái)存儲(chǔ)數(shù)據(jù),尤其是在處理 HTTP headers 時(shí)。
為什么呢?
本文將從簡(jiǎn)單到復(fù)雜,逐步剖析為什么 Fasthttp 選擇使用 slice 而非 map,并通過(guò)代碼示例解釋這一選擇背后高性能的原因
Slice vs Map:基本概念
首先,這個(gè)設(shè)計(jì)選擇背后有著深思熟慮的考量,主要圍繞性能優(yōu)化展開。在深入探討之前,我們需要理解 slice 和 map 在 Go 語(yǔ)言中的基本概念和性能特點(diǎn)。
• Slice:Slice 是對(duì)數(shù)組的封裝,它提供了一個(gè)動(dòng)態(tài)大小的、靈活的視圖。Slices 的底層實(shí)際上是數(shù)組,這意味著它們的元素在內(nèi)存中是連續(xù)存儲(chǔ)的。
• Map:Map 是一種無(wú)序的鍵值對(duì)的集合,它通過(guò)哈希表實(shí)現(xiàn)。Map 提供了快速的查找、添加和刪除操作,但這些操作的性能并不總是穩(wěn)定。
內(nèi)存分配和性能
在高性能的應(yīng)用場(chǎng)景中,內(nèi)存分配和回收是性能的關(guān)鍵因素之一。Fasthttp 在這方面做了考量。
Slice 的內(nèi)存效率
由于 slice 的元素在內(nèi)存中是連續(xù)存儲(chǔ)的,它們?cè)L問(wèn)速度快,且能有效利用 CPU 緩存。此外,slice 可以通過(guò)重新切片來(lái)復(fù)用已有的數(shù)組,減少內(nèi)存分配和垃圾回收的壓力。
Map 的內(nèi)存開銷
相比之下,map 的內(nèi)存開銷較大。
在 map 中,鍵和值通常是散布在內(nèi)存中的,這導(dǎo)致 CPU 緩存利用率不高。而且,map 的增長(zhǎng)通常涉及重新哈希和重新分配內(nèi)存,這些操作在性能敏感的應(yīng)用中可能成為瓶頸。
Fasthttp 中的 SliceMap
Fasthttp 選擇使用自定義的 sliceMap
結(jié)構(gòu)來(lái)存儲(chǔ)鍵值對(duì),而非標(biāo)準(zhǔn)的 map。
下面是 sliceMap
的一個(gè)簡(jiǎn)化實(shí)現(xiàn)和它的 Add
方法:
type kv struct { key []byte value []byte } type sliceMap []kv func (sm *sliceMap) Add(k, v []byte) { kvs := *sm if cap(kvs) > len(kvs) { kvs = kvs[:len(kvs)+1] } else { kvs = append(kvs, kv{}) } kv := &kvs[len(kvs)-1] kv.key = append(kv.key[:0], k...) kv.value = append(kv.value[:0], v...) *sm = kvs }
在這個(gè)設(shè)計(jì)中,sliceMap
通過(guò)以下方式優(yōu)化性能:
減少內(nèi)存分配
通過(guò)在現(xiàn)有的 slice 上進(jìn)行操作,sliceMap
盡可能地復(fù)用內(nèi)存。當(dāng)容量足夠時(shí),它通過(guò)重新切片 kvs = kvs[:len(kvs)+1]
來(lái)擴(kuò)展 slice,避免了額外的內(nèi)存分配。
減少垃圾回收壓力
由于 slice 的元素是連續(xù)存儲(chǔ)的,它可以更有效地被垃圾回收器處理,減少了垃圾回收的開銷。而且,由于內(nèi)存是復(fù)用的,垃圾回收的次數(shù)也大大減少。
性能優(yōu)化的深層原因
Fasthttp 使用 sliceMap
而非 map 的決策不僅僅是基于內(nèi)存和性能的考量,還有更深層的原因:
存儲(chǔ)數(shù)據(jù)特性
在處理 HTTP 請(qǐng)求時(shí),通常 headers、query 參數(shù)或 cookies 的數(shù)量并不多。這意味著即使使用線性搜索,查找效率也不會(huì)成為性能瓶頸。
相比之下,雖然 hash map 提供了理論上接近 O(1) 的查找效率,但實(shí)際使用中也有其開銷和復(fù)雜性。
• 首先,hash map 的哈希計(jì)算本身就需要時(shí)間。
• 其次,哈希碰撞時(shí),hash map 要額外處理來(lái)解決碰撞,這可能涉及到鏈表遍歷或重新哈希等操作。
這些因素在元素?cái)?shù)量較少時(shí)可能會(huì)抵消 hash map 在查找效率上的理論優(yōu)勢(shì),而 slice 則才是更優(yōu)質(zhì)的選擇。
CPU 預(yù)加載特性
由于 slice 的內(nèi)存布局是連續(xù)的,它符合 CPU 緩存的工作原理,即一次性加載相鄰數(shù)據(jù)。這種連續(xù)性使得 CPU 在訪問(wèn)一個(gè) slice 元素后,能預(yù)加載相鄰元素到緩存中,提高后續(xù)訪問(wèn)的速度。
因此,順序訪問(wèn) slice 時(shí),緩存命中率高,減少了對(duì)主內(nèi)存的訪問(wèn)次數(shù),從而提高了性能。
結(jié)論
Fasthttp 的設(shè)計(jì)選擇反映了對(duì)性能細(xì)節(jié)的深入理解和精心優(yōu)化。通過(guò)使用 slice 而非 map,F(xiàn)asthttp 在內(nèi)存分配、垃圾回收以及 CPU 緩存利用等方面實(shí)現(xiàn)了優(yōu)化,為高性能的 HTTP 應(yīng)用提供了堅(jiān)實(shí)的基礎(chǔ)。這種設(shè)計(jì)不僅僅是技術(shù)上的選擇,更是對(duì)實(shí)際應(yīng)用場(chǎng)景和性能需求的深入洞察。
以上就是Golang Fasthttp選擇使用slice而非map 存儲(chǔ)請(qǐng)求數(shù)據(jù)原理探索的詳細(xì)內(nèi)容,更多關(guān)于Golang Fasthttp slice存儲(chǔ)數(shù)據(jù)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Golang實(shí)現(xiàn)AES加密和解密的示例代碼
AES( advanced encryption standard)使用相同密鑰進(jìn)行加密和解密,也就是對(duì)稱加密。本文將詳細(xì)講解Golang實(shí)現(xiàn)AES加密和解密的方法,感興趣的可以學(xué)習(xí)一下2022-05-05golang 對(duì)私有函數(shù)進(jìn)行單元測(cè)試的實(shí)例
這篇文章主要介紹了golang 對(duì)私有函數(shù)進(jìn)行單元測(cè)試的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-05-05golang sql連接池的實(shí)現(xiàn)方法詳解
database/sql是golang的標(biāo)準(zhǔn)庫(kù)之一,它提供了一系列接口方法,用于訪問(wèn)關(guān)系數(shù)據(jù)庫(kù)。下面這篇文章主要給大家介紹了關(guān)于golang sql連接池用法的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面來(lái)一起看看吧2018-09-09golang?熔斷器的實(shí)現(xiàn)過(guò)程
這篇文章主要介紹了golang?熔斷器的實(shí)現(xiàn)過(guò)程,Go?項(xiàng)目中使用熔斷技術(shù)提高系統(tǒng)容錯(cuò)性。接下倆就來(lái)給打家介紹?go?熔斷器和其使用,需要的朋友可以參考一下2022-01-01深入探討Go語(yǔ)言中的預(yù)防性接口為什么是不必要的
在Go語(yǔ)言中,有一種從其他語(yǔ)言帶來(lái)的常見(jiàn)模式:預(yù)防性接口,雖然這種模式在?Java?等語(yǔ)言中很有價(jià)值,但在Go中往往會(huì)成為反模式,本文我們就來(lái)深入探討一下原因2025-01-01Go語(yǔ)言進(jìn)行多時(shí)區(qū)時(shí)間轉(zhuǎn)換的示例代碼
本文介紹了使用Go語(yǔ)言進(jìn)行多時(shí)區(qū)時(shí)間轉(zhuǎn)換,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-12-12