<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Go 語(yǔ)言中 sync.Mutex 的實(shí)現(xiàn)

      鎖的獲取和釋放模式

      先理解兩種不同的鎖的獲取和釋放模式"Barging" 和 "Handoff",它們影響著等待鎖的 goroutines 的行為。

      Barging(插隊(duì))

      在 Barging 模式下,當(dāng)一個(gè)鎖被釋放時(shí),任何嘗試獲取該鎖的 goroutine 都有機(jī)會(huì)立即搶占("插隊(duì)")并嘗試獲取鎖,而不管是否有其他 goroutines 正在等待。這意味著新到達(dá)的 goroutine 可能會(huì)在等待的 goroutine 之前獲取鎖,即使那些 goroutine 已經(jīng)在等待隊(duì)列中等待了一段時(shí)間。

      優(yōu)點(diǎn):是它可以減少喚醒等待線程的延遲,因?yàn)椴恍枰@式地從等待隊(duì)列中選擇一個(gè)線程并喚醒它。這可以提高性能,特別是在鎖的競(jìng)爭(zhēng)不是很激烈的情況下。

      缺點(diǎn):是可能導(dǎo)致 "饑餓",即某些 goroutine 可能會(huì)被不斷地插隊(duì),從而無(wú)法及時(shí)獲取鎖。

      如上圖,Barging 模式既會(huì)喚醒等待者 G2,G3 作為新到達(dá)的 gorouting 也有機(jī)會(huì)直接獲得鎖

       

      Handoff(交接)

      在 Handoff 模式下,當(dāng)一個(gè)鎖被釋放時(shí),持有鎖的 goroutine 顯式地將鎖交給等待隊(duì)列中的下一個(gè) goroutine。這意味著鎖的所有權(quán)從釋放鎖的 goroutine 直接傳遞給等待隊(duì)列中的一個(gè)特定 goroutine,而不允許其他 goroutine 插隊(duì)。

      優(yōu)點(diǎn):是它可以防止饑餓,因?yàn)榈却龝r(shí)間最長(zhǎng)的 goroutine 將被優(yōu)先考慮。這種模式確保了公平性,因?yàn)槊總€(gè) goroutine 都會(huì)按照它們到達(dá)等待隊(duì)列的順序獲得服務(wù)。

      缺點(diǎn):可能會(huì)引入額外的延遲,因?yàn)樾枰@式地管理等待隊(duì)列,并在每次釋放鎖時(shí)喚醒特定的 goroutine。

      如上圖,Handoff 模式喚醒等待隊(duì)列中的 G2,之后直接把鎖交接給 G2,即使喚醒過(guò)程中 G3、G4 正在請(qǐng)求鎖

       

      Go 語(yǔ)言中的實(shí)現(xiàn)

      在 Go 語(yǔ)言的 sync.Mutex 實(shí)現(xiàn)中,為了平衡性能和公平性,采用了一種混合的策略。在某些情況下,它允許 Barging,以減少喚醒等待 goroutine 的開(kāi)銷(xiāo);在其他情況下,它使用 Handoff,以確保長(zhǎng)時(shí)間等待的 goroutine 最終能夠獲取鎖,從而防止饑餓。

      Go 1.9 引入了一些改進(jìn),使得 sync.Mutex 更加傾向于公平性,通過(guò)引入一個(gè)饑餓狀態(tài),當(dāng)一個(gè) goroutine 等待超過(guò)一定的時(shí)間閾值(1ms)時(shí),它會(huì)進(jìn)入饑餓狀態(tài)。在饑餓狀態(tài)下,鎖的所有權(quán)會(huì)直接從解鎖的 goroutine 交給等待隊(duì)列中的下一個(gè) goroutine,這類(lèi)似于 Handoff 模式。當(dāng)沒(méi)有 goroutine 處于饑餓狀態(tài)時(shí),鎖的獲取更加自由,可能會(huì)出現(xiàn) Barging。

      這種混合策略旨在在高并發(fā)場(chǎng)景下提供良好的性能,同時(shí)在鎖競(jìng)爭(zhēng)激烈時(shí)保持足夠的公平性,以避免饑餓問(wèn)題。

       

      自旋 

      自旋(spinning)是一種優(yōu)化技術(shù),用于在某些情況下避免 goroutine 在等待鎖時(shí)立即進(jìn)入休眠狀態(tài)。自旋可以讓 goroutine 在短時(shí)間內(nèi)忙等(busy-wait),以期在這段時(shí)間內(nèi)鎖被釋放,從而避免了系統(tǒng)調(diào)用的開(kāi)銷(xiāo)和上下文切換的成本。

      自旋在 Go 的 sync.Mutex 中是這樣使用的:

      自旋嘗試:當(dāng)一個(gè) goroutine 嘗試獲取一個(gè)已經(jīng)被其他 goroutine 持有的鎖時(shí),它會(huì)執(zhí)行一個(gè)有限次數(shù)的自旋嘗試。在這個(gè)過(guò)程中,goroutine 會(huì)在用戶空間中忙等,檢查鎖是否已經(jīng)被釋放。

      退讓:如果在自旋嘗試期間鎖沒(méi)有被釋放,goroutine 可能會(huì)調(diào)用 runtime.Gosched() 或類(lèi)似的函數(shù)來(lái)讓出 CPU 時(shí)間片,給其他 goroutine 執(zhí)行的機(jī)會(huì)。這樣做可以減少 CPU 的無(wú)效消耗,尤其是在單核心或者核心數(shù)較少的情況下。

      阻塞:如果自旋后鎖仍然不可用,goroutine 最終會(huì)停止自旋,并通過(guò)更重的同步機(jī)制(如 futex 或其他內(nèi)核同步原語(yǔ))進(jìn)入休眠狀態(tài),等待被喚醒。

       

      自旋與 Barging 和 Handoff 模式的關(guān)系

      與 Barging 的關(guān)系:自旋與 Barging 模式結(jié)合得很好,因?yàn)樵?Barging 模式下,鎖一旦被釋放,任何 goroutine 都有機(jī)會(huì)獲取它。因此,自旋的 goroutine 可能會(huì)在鎖釋放時(shí)立即獲取到鎖,而不需要被喚醒。

      與 Handoff 的關(guān)系:在 Handoff 模式下,鎖的所有權(quán)直接從釋放鎖的 goroutine 傳遞給等待隊(duì)列中的下一個(gè) goroutine。在這種情況下,自旋可能不那么有效,因?yàn)殒i的獲取是預(yù)定的,不會(huì)立即發(fā)生。但是,如果等待隊(duì)列中沒(méi)有饑餓的 goroutine,那么自旋的 goroutine 仍然有機(jī)會(huì)在鎖釋放時(shí)立即獲取它。

      Go 語(yǔ)言的運(yùn)行時(shí)會(huì)根據(jù)當(dāng)前的情況(如鎖的競(jìng)爭(zhēng)程度和處理器的數(shù)量)來(lái)決定是否使用自旋,以及自旋的次數(shù)。這是一個(gè)經(jīng)過(guò)調(diào)優(yōu)的決策,目的是在減少延遲和避免浪費(fèi) CPU 資源之間找到平衡點(diǎn)。

      sync_runtime_canSpin 判斷是否可以進(jìn)入自旋

      // Active spinning for sync.Mutex.
      //go:linkname sync_runtime_canSpin sync.runtime_canSpin
      //go:nosplit
      func sync_runtime_canSpin(i int) bool {
          // sync.Mutex is cooperative, so we are conservative with spinning.
          // Spin only few times and only if running on a multicore machine and
          // GOMAXPROCS>1 and there is at least one other running P and local runq is empty.
          // As opposed to runtime mutex we don't do passive spinning here,
          // because there can be work on global runq or on other Ps.
          if i >= active_spin || ncpu <= 1 || gomaxprocs <= int32(sched.npidle+sched.nmspinning)+1 {
              return false
          }
          if p := getg().m.p.ptr(); !runqempty(p) {
              return false
          }
          return true
      }

       

       

      如果可以自選,就通過(guò) sync_runtime_doSpin 進(jìn)入自旋,對(duì)應(yīng)執(zhí)行 30 次 PAUSE 指令

      PAUSE 指令會(huì)告訴 CPU 我當(dāng)前處于處于自旋狀態(tài),這時(shí)候 CPU 會(huì)針對(duì)性的做一些優(yōu)化,并且在執(zhí)行這個(gè)指令的時(shí)候 CPU 會(huì)降低自己的功耗,減少能源消耗

      //go:linkname sync_runtime_doSpin sync.runtime_doSpin
      //go:nosplit
      func sync_runtime_doSpin() {
          procyield(active_spin_cnt)
      }
      
      TEXT runtime·procyield(SB),NOSPLIT,$0-0
          MOVL    cycles+0(FP), AX
      again:
          PAUSE
          SUBL    $1, AX
          JNZ    again
          RET

       

      Mutex 源碼結(jié)構(gòu)

      // A Mutex is a mutual exclusion lock.
      // The zero value for a Mutex is an unlocked mutex.
      //
      // A Mutex must not be copied after first use.
      type Mutex struct {
          state int32
          sema  uint32
      }
      
      mutexLocked = 1 << iota // mutex is locked
      mutexWoken
      mutexStarving
      mutexWaiterShift = iota

        

      state:4 字節(jié)的 Int32 類(lèi)型,最低的 3 個(gè) bit 表示鎖的狀態(tài),分別是 mutexLocked  mutexWoken mutexStarving ,剩下的 bit 用于統(tǒng)計(jì)當(dāng)前在等待鎖的 goroutine 數(shù)量

      sema:控制 gorouting 在獲取鎖過(guò)程當(dāng)中的休眠和喚醒,在 Linux 系統(tǒng)中,信號(hào)量可以通過(guò)多種方式實(shí)現(xiàn),其中之一是使用 "futex"(快速用戶空間互斥鎖)。futex 是一種系統(tǒng)調(diào)用,它提供了一種在用戶空間線程之間進(jìn)行高效等待和喚醒的機(jī)制

       

      Lock 方法

      Fast Path:首先嘗試一個(gè)快速路徑,如果鎖是空閑的(state 為 0),就通過(guò)原子操作 CompareAndSwapInt32 嘗試將其設(shè)置為 mutexLocked 狀態(tài)。如果成功,就直接返回,表示獲取鎖成功。

      Slow Path:如果快速路徑失敗,表示鎖已經(jīng)被其他 goroutine 持有,那么就進(jìn)入慢路徑。在慢路徑中,會(huì)有一個(gè)循環(huán),goroutine 會(huì)在這里等待,直到它能夠獲取鎖。

      Starvation Detection: 代碼中有對(duì)饑餓狀態(tài)的檢測(cè),如果一個(gè) goroutine 長(zhǎng)時(shí)間等待鎖,它可能會(huì)進(jìn)入饑餓模式,這時(shí)它會(huì)被優(yōu)先喚醒。

      Waiters Counting: 如果鎖已經(jīng)被持有,goroutine 會(huì)增加等待者的計(jì)數(shù),并可能進(jìn)入休眠狀態(tài),等待鎖被釋放。

      Waking Up: 當(dāng)鎖被釋放時(shí),等待的 goroutine 會(huì)被喚醒。如果有多個(gè)等待者,喚醒操作會(huì)嘗試保持公平性,避免某些 goroutine 饑餓。

       

      Unlock 方法

      Fast Path: 通過(guò)原子操作減少 state 的值來(lái)釋放鎖。如果減少后的值表明鎖已經(jīng)是未鎖定狀態(tài),那么會(huì)拋出 panic,因?yàn)檫@意味著試圖釋放一個(gè)未鎖定的互斥鎖。

      No Waiters: 如果沒(méi)有等待者,或者已經(jīng)有一個(gè) goroutine 被喚醒或處于饑餓狀態(tài),那么就沒(méi)有必要進(jìn)行喚醒操作。

      Wake Someone Up: 如果有等待者,那么會(huì)釋放一個(gè)信號(hào)量 sema 來(lái)喚醒一個(gè)等待的 goroutine。

       

      參考:

      1. https://lailin.xyz/post/go-training-week3-sync.html#RWMutex

      2. https://pkg.go.dev/sync 

      posted @ 2024-04-15 16:01  JL_Zhou  閱讀(209)  評(píng)論(0)    收藏  舉報(bào)
      主站蜘蛛池模板: 亚洲av成人一区在线| 青青草一区在线观看视频| 日韩精品卡一卡二卡三卡四| 国产成人一区二区三区在线| 国产360激情盗摄全集| 人人色在线视频播放| 亚洲欧洲一区二区综合精品 | 天天爽夜夜爽人人爽曰| 新郑市| 九九视频热最新在线视频| av午夜福利一片免费看久久| 强奷漂亮人妻系列老师| 黑巨人与欧美精品一区| 国产中文字幕精品在线| 免费看一区无码无a片www| 久久婷婷大香萑太香蕉AV人| 国产国产成人精品久久蜜| 国产精品视频一区不卡| 国产成人精品无码播放| 欧洲人与动牲交α欧美精品| 国产综合欧美| 日韩视频一区二区三区视频| 东北妇女精品bbwbbw| 韩国精品福利视频一区二区| 国产一区日韩二区欧美三区| 亚洲精品欧美综合二区| 国产精品亚洲а∨无码播放| 国产女同一区二区在线| 国产真实精品久久二三区| 国产成人无码区免费内射一片色欲| 在线国产精品中文字幕| 国产成人午夜福利在线播放| 美女扒开奶罩露出奶头视频网站| 免费国产精品黄色一区二区| 国产精品区一区第一页| 新巴尔虎左旗| 中文人妻AV高清一区二区| 国产精品一区二区av片| 亚洲熟女一区二区av| 无码任你躁久久久久久老妇| 国产av综合一区二区三区|