C++編程經驗(10):無鎖編程其實沒那么玄乎
1018
2025-04-01
1、Go 語言當中數組和切片的區別是什么?
數組:
數組固定長度數組長度是數組類型的一部分,所以[3]int 和[4]int 是兩種不同 的數組類型數組需要指定大小,不指定也會根據處初始化對的自動推算出大 小,不可改變數組是通過值傳遞的
切片: 切片可以改變長度切片是輕量級的數據結構,三個屬性,指針,長度,容量不 需要指定大小切片是地址傳遞(引用傳遞)可以通過數組來初始化,也可以通 過內置函數 make()來初始化,初始化的時候 len=cap,然后進行擴容。
2、Go 語言當中值傳遞和地址傳遞(引用傳遞)如何運用?有什么區別?
值傳遞只會把參數的值復制一份放進對應的函數,兩個變量的地址不同, 不可相互修改。
地址傳遞(引用傳遞)會將變量本身傳入對應的函數,在函數中可以對該變 量進行值內容的修改。
3、Go 語言當中數組和切片在傳遞的時候的區別是什么?
數組是值傳遞
切片是引用傳遞
4、Go 語言是如何實現切片擴容的?
func?main()?{
arr?:=?make([]int,?0)
for?i?:=?0;?i?2000;?i++?{
fmt.Println("len?為",?len(arr),?"cap?為",?cap(arr))
arr?=?append(arr,?i)
}
}
我們可以看下結果
依次是0,1,2,4,8,16,32,64,128,256,512,1024
但到了 1024 之后,就變成了1024,1280,1696,2304
每次都是擴容了四分之一左右
5、看下面代碼的 defer 的執行順序是什么? defer 的作用和特點是什么?
defer 的作用是:
你只需要在調用普通函數或方法前加上關鍵字 defer,就完成了 defer 所需要 的語法。當 defer 語句被執行時,跟在 defer 后面的函數會被延遲執行。直到 包含該 defer 語句的函數執行完畢時,defer 后的函數才會被執行,不論包含defer 語句的函數是通過 return 正常結束,還是由于 panic 導致的異常結束。你可以在一個函數中執行多條 defer 語句,它們的執行順序與聲明順序相反。
defer 的常用場景:
defer語句經常被用于處理成對的操作,如打開、關閉、連接、斷開連接、加鎖、釋放鎖。
通過defer機制,不論函數邏輯多復雜,都能保證在任何執行路徑下,資
源被釋放。
釋放資源的defer應該直接跟在請求資源的語句后。
6、golang Slice 的底層實現
切片是基于數組實現的,它的底層是數組,它自己本身非常小,可以理解為對底層數組的抽象。因為基于數組實現,所以它的底層的內存是連續分配的,效率非常高,還可以通過索引獲得數據,可以迭代以及垃圾回收優化。
切片本身并不是動態數組或者數組指針。它內部實現的數據結構通過指針引用 底層數組,設定相關屬性將數據讀寫操作限定在指定的區域內。切片本身是一 個只讀對象,其工作機制類似數組指針的一種封裝。
切片對象非常小,是因為它是只有 3 個字段的數據結構:
指向底層數組的指針
切片的長度
切片的容量
7、golang Slice 的擴容機制,有什么注意點?
Go 中切片擴容的策略是這樣的:
首先判斷,如果新申請容量大于2倍的舊容量,最終容量就是新申請的容 量
否則判斷,如果舊切片的長度小于1024,則最終容量就是舊容量的兩倍
否則判斷,如果舊切片長度大于等于1024,則最終容量從舊容量開始循環
增加原來的 1/4, 直到最終容量大于等于新申請的容量
如果最終容量計算值溢出,則最終容量就是新申請容量
8、擴容前后的 Slice 是否相同?
情況一:
原數組還有容量可以擴容(實際容量沒有填充完),這種情況下,擴容以后的 數組還是指向原來的數組,對一個切片的操作可能影響多個指針指向相同地址 的 Slice。
情況二:
原來數組的容量已經達到了最大值,再想擴容, Go 默認會先開一片內存區 域,把原來的值拷貝過來,然后再執行 append() 操作。這種情況絲毫不影響 原數組。
要復制一個 Slice,最好使用 Copy 函數。
9、Golang 的參數傳遞、引用類型
Go 語言中所有的傳參都是值傳遞(傳值),都是一個副本,一個拷貝。因為拷 貝的內容有時候是非引用類型(int、string、struct 等這些),這樣就在函 數中就無法修改原內容數據;有的是引用類型(指針、map、slice、chan等 這些),這樣就可以修改原內容數據。
Golang 的引用類型包括 slice、map 和 channel。它們有復雜的內部結構,除 了申請內存外,還需要初始化相關屬性。內置函數 new 計算類型大小,為其分 配零值內存,返回指針。而 make 會被編譯器翻譯成具體的創建函數,由其分 配內存和初始化成員結構,返回對象而非指針。
10、Golang Map 底層實現
Golang 中 map 的底層實現是一個散列表,因此實現 map 的過程實際上就是實現 散表的過程。在這個散列表中,主要出現的結構體有兩個,一個叫 hmap(a header for a go map),一個叫 bmap(a bucket for a Go map,通常叫其bucket)。
11、Golang Map 如何擴容
裝載因子:count/2^B
觸發條件:
1. 裝填因子是否大于6.5
2. overflow bucket 是否太多
解決方法:
1. 雙倍擴容:擴容采取了一種稱為“漸進式”地方式,原有的 key 并不會一
次性搬遷完畢,每次最多只會搬遷 2 個 bucket
2. 等量擴容:重新排列,極端情況下,重新排列也解決不了,map成了鏈表,
性能大大降低,此時哈希種子 hash0 的設置,可以降低此類極端場景的發 生。
12、Golang Map 查找
Go 語言中 map 采用的是哈希查找表,由一個 key 通過哈希函數得到哈希值,64位系統中就生成一個 64bit 的哈希值,由這個哈希值將 key 對應到不同的桶 (bucket)中,當有多個哈希映射到相同的的桶中時,使用鏈表解決哈希沖 突。key 經過 hash 后共 64 位,根據 hmap 中 B 的值,計算它到底要落在哪個桶 時,桶的數量為 2^B,如 B=5,那么用 64 位最后 5 位表示第幾號桶,在用 hash值的高 8 位確定在 bucket 中的存儲位置,當前 bmap 中的 bucket 未找到,則查 詢對應的 overflow bucket,對應位置有數據則對比完整的哈希值,確定是否 是要查找的數據。
如果兩個不同的 key 落在的同一個桶上,hash 沖突使用鏈表法接近,遍歷bucket 中的 key 如果當前處于 map 進行了擴容,處于數據搬移狀態,則優先從oldbuckets 查找。
13、介紹一下 Channel
Go 語言中,不要通過共享內存來通信,而要通過通信來實現內存共享。Go 的CSP(Communicating Sequential Process)并發模型,中文可以叫做通信順序進 程,是通過 goroutine 和 channel 來實現的。
所以 channel 收發遵循先進先出 FIFO,分為有緩存和無緩存,channel 中大致 有 buffer(當緩沖區大小部位 0 時,是個 ring buffer)、sendx 和 recvx 收發 的位置(ring buffer 記錄實現)、sendq、recvq 當前 channel 因為緩沖區不足 而阻塞的隊列、使用雙向鏈表存儲、還有一個 mutex 鎖控制并發、其他原屬 等。
14、Go 語言的 Channel 特性?
給一個 nil channel 發送數據,造成永遠阻塞
從一個 nil channel 接收數據,造成永遠阻塞
給一個已經關閉的 channel 發送數據,引起 panic
從一個已經關閉的 channel 接收數據,如果緩沖區中為空,則返回一個零值
無緩沖的channel是同步的,而有緩沖的channel是非同步的
關閉一個 nil channel 將會發生 panic
15、Channel 的 ring buffer 實現
channel 中使用了 ring buffer(環形緩沖區) 來緩存寫入的數據。ring buffer 有很多好處,而且非常適合用來實現 FIFO 式的固定長度隊列。在 channel 中,ring buffer 的實現如下:
hchan 中有兩個與 buffer 相關的變量:recvx 和 sendx。其中 sendx 表示buffer 中可寫的 index,recvx 表示 buffer 中可讀的 index。從 recvx 到sendx 之間的元素,表示已正常存放入 buffer 中的數據。
我們可以直接使用 buf[recvx]來讀取到隊列的第一個元素,使用 buf[sendx] = x 來將元素放到隊尾。
最后:
點擊下方名片鏈接,關注 「碼農編程進階筆記?」微信公眾號,在微信聊天對話框回復「go電子書」「黑馬Go語言」或者直接長按左下圖海報中的二維碼,可獲取最新golang電子書和視頻資源
Go 數據結構
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。