字節(jié)跳動Go 語言面試會問哪些問題?

      網(wǎng)友投稿 783 2022-05-29

      1、Mutex 幾種狀態(tài)

      mutexLocked?— 表示互斥鎖的鎖定狀態(tài);

      mutexWoken?— 表示從正常模式被從喚醒;

      mutexStarving?— 當前的互斥鎖進入饑餓狀態(tài);

      waitersCount?— 當前互斥鎖上等待的 Goroutine 個數(shù);

      2、Mutex 正常模式和饑餓模式正常模式(非公平鎖)

      正常模式下,所有等待鎖的 goroutine 按照 FIFO(先進先出)順序等待。喚醒的goroutine 不會直接擁有鎖,而是會和新請求鎖的 goroutine 競爭鎖的擁有。新請求鎖的 goroutine 具有優(yōu)勢:它正在 CPU 上執(zhí)行,而且可能有好幾個,所 以剛剛喚醒的 goroutine 有很大可能在鎖競爭中失敗。在這種情況下,這個被 喚醒的 goroutine 會加入到等待隊列的前面。如果一個等待的 goroutine 超過1ms 沒有獲取鎖,那么它將會把鎖轉(zhuǎn)變?yōu)轲囸I模式。

      饑餓模式(公平鎖)

      為了解決了等待 G 隊列的長尾問題

      饑餓模式下,直接由 unlock 把鎖交給等待隊列中排在第一位的 G(隊頭),同 時,饑餓模式下,新進來的 G 不會參與搶鎖也不會進入自旋狀態(tài),會直接進入 等待隊列的尾部,這樣很好的解決了老的 g 一直搶不到鎖的場景。饑餓模式的觸發(fā)條件,當一個 G 等待鎖時間超過 1 毫秒時,或者當前隊列只剩 下一個 g 的時候,Mutex 切換到饑餓模式。

      總結(jié)

      對于兩種模式,正常模式下的性能是最好的,goroutine 可以連續(xù)多次獲取 鎖,饑餓模式解決了取鎖公平的問題,但是性能會下降,其實是性能和公平的 一個平衡模式。

      3、Mutex 允許自旋的條件

      1 鎖已被占用,并且鎖不處于饑餓模式。

      2 積累的自旋次數(shù)小于最大自旋次數(shù)(active_spin=4)。3 cpu 核數(shù)大于 1。

      4 有空閑的 P。

      5 當前 goroutine 所掛載的 P 下,本地待運行隊列為空。

      4、RWMutex 實現(xiàn)

      通過記錄 readerCount 讀鎖的數(shù)量來進行控制,當有一個寫鎖的時候,會將讀 鎖數(shù)量設(shè)置為負數(shù) 1<<30。目的是讓新進入的讀鎖等待寫鎖之后釋放通知讀 鎖。同樣的寫鎖也會等等待之前的讀鎖都釋放完畢,才會開始進行后續(xù)的操 作。而等寫鎖釋放完之后,會將值重新加上 1<<30, 并通知剛才新進入的讀鎖(rw.readerSem),兩者互相限制。

      5、RWMutex 注意事項

      RWMutex 是單寫多讀鎖,該鎖可以加多個讀鎖或者一個寫鎖

      讀鎖占用的情況下會阻止寫,不會阻止讀,多個goroutine 可以同時獲取讀鎖

      寫鎖會阻止其他 goroutine(無論讀和寫)進來,整個鎖由該 goroutine獨占

      適用于讀多寫少的場景

      RWMutex 類型變量的零值是一個未鎖定狀態(tài)的互斥鎖。

      RWMutex 在首次被使用之后就不能再被拷貝。

      RWMutex 的讀鎖或?qū)戞i在未鎖定狀態(tài),解鎖操作都會引發(fā) panic。

      RWMutex 的一個寫鎖?Lock?去鎖定臨界區(qū)的共享資源,如果臨界區(qū)的共享資源已被(讀鎖或?qū)戞i)鎖定,這個寫鎖操作的 goroutine 將被阻塞直到解鎖。

      RWMutex 的讀鎖不要用于遞歸調(diào)用,比較容易產(chǎn)生死鎖。

      RWMutex 的鎖定狀態(tài)與特定的 goroutine 沒有關(guān)聯(lián)。一個 goroutine 可以 RLock(Lock),另一個 goroutine 可以 RUnlock(Unlock)。

      寫鎖被解鎖后,所有因操作鎖定讀鎖而被阻塞的 goroutine 會被喚醒,并都可以成功鎖定讀鎖。

      字節(jié)跳動Go 語言面試會問哪些問題?

      讀鎖被解鎖后,在沒有被其他讀鎖鎖定的前提下,所有因操作鎖定寫鎖而被阻塞的 goroutine,其中等待時間最長的一個 goroutine 會被喚醒。

      6、Cond 是什么

      Cond 實現(xiàn)了一種條件變量,可以使用在多個 Reader 等待共享資源 ready 的場 景(如果只有一讀一寫,一個鎖或者 channel 就搞定了)

      每個 Cond 都會關(guān)聯(lián)一個 Lock(*sync.Mutex or *sync.RWMutex),當修改條 件或者調(diào)用 Wait 方法時,必須加鎖,保護 condition。

      7、Broadcast 和 Signal 區(qū)別

      func?(c?*Cond)?Broadcast()

      Broadcast 會喚醒所有等待 c 的 goroutine。

      調(diào)用 Broadcast 的時候,可以加鎖,也可以不加鎖。

      func?(c?*Cond)?Signal()

      Signal 只喚醒 1 個等待 c 的 goroutine。

      調(diào)用 Signal 的時候,可以加鎖,也可以不加鎖。

      8、Cond 中 Wait 使用

      func?(c?*Cond)?Wait()

      Wait()會自動釋放 c.L,并掛起調(diào)用者的 goroutine。之后恢復(fù)執(zhí)行,Wait()會 在返回時對 c.L 加鎖。

      除非被 Signal 或者 Broadcast 喚醒,否則 Wait()不會返回。

      由于 Wait()第一次恢復(fù)時,C.L 并沒有加鎖,所以當 Wait 返回時,調(diào)用者通常 并不能假設(shè)條件為真。

      取而代之的是, 調(diào)用者應(yīng)該在循環(huán)中調(diào)用 Wait。(簡單來說,只要想使用condition,就必須加鎖。)

      for?!condition()?{

      c.Wait()

      }

      ...?make?use?of?condition?...

      c.L.Unlock()

      c.L.Lock()

      9、WaitGroup 用法

      一個 WaitGroup 對象可以等待一組協(xié)程結(jié)束。使用方法是:

      1. main 協(xié)程通過調(diào)用?wg.Add(delta int)?設(shè)置 worker 協(xié)程的個數(shù),然后創(chuàng) 建 worker 協(xié)程;

      2.worker 協(xié)程執(zhí)行結(jié)束以后,都要調(diào)用?wg.Done();

      3.main 協(xié)程調(diào)用?wg.Wait()?且被 block,直到所有 worker 協(xié)程全部執(zhí)行結(jié)束 后返回。

      10、WaitGroup 實現(xiàn)原理

      WaitGroup 主要維護了 2 個計數(shù)器,一個是請求計數(shù)器 v,一個是等待計數(shù) 器 w,二者組成一個 64bit 的值,請求計數(shù)器占高 32bit,等待計數(shù)器占低32bit。

      每次Add執(zhí)行,請求計數(shù)器v加1,Done方法執(zhí)行,請求計數(shù)器減1,v為0 時通過信號量喚醒 Wait()。

      11、什么是 sync.Once

      Once 可以用來執(zhí)行且僅僅執(zhí)行一次動作,常常用于單例對象的初始化場 景。

      Once 常常用來初始化單例資源,或者并發(fā)訪問只需初始化一次的共享資 源,或者在測試的時候初始化一次測試資源。

      sync.Once 只暴露了一個方法 Do,你可以多次調(diào)用 Do 方法,但是只有第 一次調(diào)用 Do 方法時 f 參數(shù)才會執(zhí)行,這里的 f 是一個無參數(shù)無返回值 的函數(shù)。

      12、什么操作叫做原子操作

      一個或者多個操作在 CPU 執(zhí)行過程中不被中斷的特性,稱為原子性(atomicity)。這些操作對外表現(xiàn)成一個不可分割的整體,他們要么都執(zhí)行,要 么都不執(zhí)行,外界不會看到他們只執(zhí)行到一半的狀態(tài)。而在現(xiàn)實世界中,CPU不可能不中斷的執(zhí)行一系列操作,但如果我們在執(zhí)行多個操作時,能讓他們的 中間狀態(tài)對外不可見,那我們就可以宣城他們擁有了“不可分割”的原子性。

      在 Go 中,一條普通的賦值語句其實不是一個原子操作。列如,在 32 位機器上 寫 int64 類型的變量就會有中間狀態(tài),因為他會被拆成兩次寫操作(MOV)——寫 低32位和寫高32位。

      13、原子操作和鎖的區(qū)別

      原子操作由底層硬件支持,而鎖則由操作系統(tǒng)的調(diào)度器實現(xiàn)。鎖應(yīng)當用來保護 一段邏輯,對于一個變量更新的保護,原子操作通常會更有效率,并且更能利 用計算機多核的優(yōu)勢,如果要更新的是一個復(fù)合對象,則應(yīng)當使用atomic.Value 封裝好的實現(xiàn)。

      14、什么是 CAS

      CAS 的全稱為 Compare And Swap,直譯就是比較交換。是一條 CPU 的原子指 令,其作用是讓 CPU 先進行比較兩個值是否相等,然后原子地更新某個位置的 值,其實現(xiàn)方式是給予硬件平臺的匯編指令,在 intel 的 CPU 中,使用的cmpxchg 指令,就是說 CAS 是靠硬件實現(xiàn)的,從而在硬件層面提升效率。

      簡述過程是這樣:

      假設(shè)包含 3 個參數(shù)內(nèi)存位置(V)、預(yù)期原值(A)和新值(B)。V 表示要更新變量的 值,E 表示預(yù)期值,N 表示新值。僅當 V 值等于 E 值時,才會將 V 的值設(shè)為 N, 如果 V 值和 E 值不同,則說明已經(jīng)有其他線程在做更新,則當前線程什么都不 做,最后 CAS 返回當前 V 的真實值。CAS 操作時抱著樂觀的態(tài)度進行的,它總 是認為自己可以成功完成操作。基于這樣的原理,CAS 操作即使沒有鎖,也可 以發(fā)現(xiàn)其他線程對于當前線程的干擾。

      15、sync.Pool 有什么用

      對于很多需要重復(fù)分配、回收內(nèi)存的地方,sync.Pool 是一個很好的選擇。頻 繁地分配、回收內(nèi)存會給 GC 帶來一定的負擔,嚴重的時候會引起 CPU 的毛 刺,而 sync.Pool 可以將暫時不用的對象緩存起來,待下次需要的時候直接 使用,不用再次經(jīng)過內(nèi)存分配,復(fù)用對象的內(nèi)存,減輕 GC 的壓力,提升系統(tǒng) 的性能。

      最后:

      點擊下方名片鏈接,關(guān)注 「碼農(nóng)編程進階筆記?」微信公眾號,在微信聊天對話框回復(fù)「go語言實戰(zhàn)」「goweb編程」或者直接長按左下圖海報中的二維碼,可獲取最新golang電子書和視頻資源

      Go

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔相應(yīng)法律責任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。

      上一篇:【設(shè)計模式面試】結(jié)構(gòu)性設(shè)計模式你清楚幾個?
      下一篇:碾壓Bert?“屠榜”的XLnet對NLP任務(wù)意味著什么
      相關(guān)文章
      亚洲A∨无码一区二区三区| 亚洲色中文字幕无码AV| 亚洲AV无码成人精品区蜜桃| 中文字幕亚洲图片| 亚洲视频人成在线播放| 亚洲精品成人区在线观看| 亚洲欧美在线x视频| 亚洲AV香蕉一区区二区三区| 亚洲国产精品18久久久久久 | 亚洲国产美女在线观看| 久久精品国产亚洲AV大全| 老汉色老汉首页a亚洲| 亚洲美女视频一区二区三区| 亚洲经典在线观看| 亚洲国产av一区二区三区丶| 亚洲制服丝袜精品久久| 亚洲资源最新版在线观看| 亚洲日本国产综合高清| 亚洲成_人网站图片| 亚洲日韩精品无码专区| 亚洲AV无码资源在线观看| 18禁亚洲深夜福利人口| 亚洲国产精品毛片av不卡在线| vvvv99日韩精品亚洲| 国产亚洲情侣一区二区无| 亚洲乱码中文字幕综合| 久久久亚洲精品视频| 久久亚洲精品国产精品| 亚洲中文无码av永久| 亚洲综合精品成人| va亚洲va日韩不卡在线观看| 亚洲AV无码不卡在线观看下载| 亚洲小视频在线观看| 亚洲欧洲第一a在线观看| 久久青青草原亚洲av无码app | 亚洲高清国产拍精品26U| 亚洲一区二区电影| 亚洲Av高清一区二区三区| 亚洲人成自拍网站在线观看| 国产亚洲精品成人久久网站| 国产亚洲精品资在线|