每日八股文6.2

每日八股-6.2

  • Go
    • 1.GMP調度原理(這部分多去看看golang三關加深理解)
    • 2.GC(同樣多去看看golang三關加深理解)
    • 3.閉包
    • 4.go語言函數是一等公民是什么意思
    • 5.sync.Mutex和sync.RWMutex
    • 6.sync.WaitGroup
    • 7.sync.Cond
    • 8.sync.Pool
    • 9.panic和recover
    • 10.goroutine

Go

1.GMP調度原理(這部分多去看看golang三關加深理解)

Go的GMP調度模型是其并發實現的核心。

  • G (Goroutine): 代表一個協程,是Go語言中并發執行的基本單元。它非常輕量,初始棧空間很小,可以創建成千上萬個。
  • M (Machine): 代表一個內核線程 (OS Thread),是真正執行代碼的實體。M的數量通常不會太多。
  • P (Processor): 代表一個調度處理器,或者說是G和M之間的調度上下文。P的數量默認等于CPU核心數,可以通過GOMAXPROCS環境變量或運行時函數來設置。

調度流程可以概括為:

  1. 每個P會維護一個可運行的G隊列 (Local Run Queue, LRQ)。

  2. M需要獲取一個P才能執行G。M會從其綁定的P的LRQ中獲取G并執行。

  3. 如果P的LRQ為空,M會嘗試從全局G隊列 (Global Run Queue, GRQ)或其他P的LRQ中竊取 (Work Stealing) G來執行,以實現負載均衡。

  4. 當G執行系統調用或發生阻塞時,它所占用的M會和P解綁(Hand Off),P會去尋找其他空閑的M,或者創建一個新的M來繼續執行隊列中的其他G。阻塞的G結束后會嘗試重新進入某個P的隊列等待執行。

  5. 通過這種方式,GMP模型實現了高效的用戶態調度,避免了頻繁的內核態線程切換,并能充分利用多核CPU資源。

2.GC(同樣多去看看golang三關加深理解)

Go語言的垃圾回收 (GC) 主要是為了自動管理內存,減輕開發者的負擔,避免內存泄漏。

Go的GC采用的是并發的三色標記清除 (Concurrent Tri-color Mark-and-Sweep) 算法。

核心思想可以概括為:

  1. 根對象 (Roots): 從程序的全局變量、Goroutine棧上的指針等根對象開始追蹤。
  2. 三色標記:
  • 白色: 初始時所有對象都是白色,表示尚未被訪問。GC結束后,仍為白色的對象將被回收。
  • 灰色: 對象已被訪問,但其引用的其他對象尚未完全掃描。灰色對象是待處理的。
  • 黑色: 對象已被訪問,并且其引用的所有對象都已被掃描或標記為灰色。黑色對象是存活的。
  1. 標記階段 (Marking):
  • GC開始時,所有對象標記為白色。
  • 從根對象開始,將其標記為灰色并放入待掃描隊列。
  • 不斷從隊列中取出灰色對象,將其標記為黑色,并將其引用的白色對象標記為灰色放入隊列。
  • 這個標記過程是并發的,意味著應用程序的Goroutine可以和GC的標記線程同時運行,從而大大減少STW (Stop-The-World,即cpu完全用來執行垃圾回收,而不執行代碼,這樣會造成程序的卡頓) 的時間。
  1. 混合寫屏障 (Hybrid Write Barrier,融合了插入寫屏障和刪除寫屏障的思想):
  • GC 開始將棧上的可達對象全部掃描并標記為黑色 (之后不再進行第二次重復掃描,無需 STW),

  • GC 期間,任何在棧上創建的新對象,均為黑色。(混合寫屏障加入了這兩條對棧區的操作,使得不需要STW)

  • 被刪除的對象標記為灰色。(刪除寫屏障)

  • 被添加的對象標記為灰色。(插入寫屏障)

補充: 插入寫屏障:只應用于堆區,如果一個對象在并發過程中創建了一個新的對象,那么新的對象直接標記為灰色。
刪除寫屏障:如果一個對象在并發過程中被刪除,那么直接標記該刪除的對象為灰色。

  1. 清除階段 (Sweeping): 標記階段完成后,所有仍然是白色的對象就是不可達的垃圾對象。清除階段會回收這些白色對象的內存空間。這個階段也可以部分并發執行。

3.閉包

實現閉包的一個重要前提就是函數是一等公民,它可以向其它類型的參數一樣被傳遞。如果我們有一個函數,并且在這個函數里面又定義了另一個函數,且這個內部函數可以使用外部函數里面定義的變量,這就是閉包。當我們聲明一個匿名函數時,他天生就是一個閉包。

4.go語言函數是一等公民是什么意思

函數是一等公民,意味著可以把函數賦值給變量或存儲在數據結構中,也可以把函數作為其它函數的參數或者返回值。

5.sync.Mutex和sync.RWMutex

Mutex 也稱為互斥鎖,互斥鎖就是互相排斥的鎖,它可以用作保護臨界區的共享資源,保證同一時刻只有一個 goroutine 操作臨界區中的共享資源。互斥鎖 Mutex類型有兩個方法,Lock和 Unlock。

type Mutex struct {state int32 // 互斥鎖的狀態sema  uint32 // 信號量,用于控制互斥鎖的狀態
}

使用互斥鎖的注意事項

  • Mutex 類型變量的零值是一個未鎖定狀態的互斥鎖
  • Mutex 在首次被使用之后就不能再被拷貝(Mutex 是值類型,拷貝會同時拷貝互斥鎖的狀態)
  • Mutex 在未鎖定狀態(還未鎖定或已被解鎖),調用 Unlock方法,將會引發運行時錯誤
  • Mutex 的鎖定狀態與特定 goroutine 沒有關聯,Mutex 被一個 goroutine 鎖定, 可以被另外一個 goroutine 解鎖。(不建議使用,必須使用時需要格外小心)
  • Mutex 的 Lock方法和 Unlock方法要成對使用,不要忘記將鎖定的互斥鎖解鎖,一般做法是使用 defer

RWMutex 也稱為讀寫互斥鎖,讀寫互斥鎖就是讀取/寫入互相排斥的鎖。它可以由任意數量的讀取操作的 goroutine 或單個寫入操作的 goroutine 持有。讀寫互斥鎖 RWMutex 類型有五個方法,Lock,Unlock,Rlock,RUnlock 和 RLocker。其中,RLocker 返回一個 Locker 接口,該接口通過調用rw.RLock 和 rw.RUnlock 來實現 Lock 和 Unlock 方法。

type RWMutex struct {w           Mutex        // held if there are pending writerswriterSem   uint32       // semaphore for writers to wait for completing readersreaderSem   uint32       // semaphore for readers to wait for completing writersreaderCount atomic.Int32 // number of pending readersreaderWait  atomic.Int32 // number of departing readers
}

使用讀寫互斥鎖的注意事項

  • RWMutex 類型變量的零值是一個未鎖定狀態的互斥鎖
  • RWMutex 在首次被使用之后就不能再被拷貝
  • RWMutex 的讀鎖或寫鎖在未鎖定狀態,解鎖操作都會引發 panic
  • RWMutex 的一個寫鎖 Lock 去鎖定臨界區的共享資源,如果臨界區的共享資源已被(讀鎖或寫鎖)鎖定,這個寫鎖操作的 goroutine 將被阻塞直到解鎖
  • RWMutex 的讀鎖不要用于遞歸調用,比較容易產生死鎖
  • RWMutex 的鎖定狀態與特定的 goroutine 沒有關聯。一個 goroutine 可以 RLock(Lock),另一個 goroutine 可以 RUnlock(Unlock)
  • 寫鎖被解鎖后,所有因操作鎖定讀鎖而被阻塞的 goroutine 會被喚醒,并都可以成功鎖定讀鎖
  • 讀鎖被解鎖后,在沒有被其他讀鎖鎖定的前提下,所有因操作鎖定寫鎖而被阻塞的 goroutine,其中等待時間最長的一個 goroutine 會被喚醒

Mutex 和 RWMutex 的區別

  • RWMutex 將對臨界區的共享資源的讀寫操作做了區分,RWMutex 可以針對讀寫操作做不同級別的鎖保護。
  • RWMutex 讀寫鎖中包含讀鎖和寫鎖,它的 Lock和 Unlock 方法用作寫鎖保護,它的 Rlock和 RUnlock 方法用作讀鎖保護。
  • RWMutex 讀寫鎖中的讀鎖和寫鎖關系如下:
  • 在寫鎖處于鎖定狀態時,操作鎖定讀鎖的 goroutine 會被阻塞。
  • 在寫鎖處于鎖定狀態時,操作鎖定寫鎖的 goroutine 會被阻塞。
  • 在讀鎖處于鎖定狀態時,操作鎖定寫鎖的 goroutine 會被阻塞。
  • 但是,在讀鎖處于鎖定狀態時,操作鎖定讀鎖的 goroutine 不會被阻塞。我們可以理解為讀鎖保護的臨界區的共享資源,多個讀操作可以同時執行

6.sync.WaitGroup

sync.WaitGroup 用于阻塞等待一組 Go 程的結束。如果有一個任務可以分解成多個子任務進行處理,同時每個子任務沒有先后執行順序的限制,等到全部子任務執行完畢后,再進行下一步處理。這時每個子任務的執行可以并發處理,這種情景下適合使用sync.WaitGroup。

標準用法

  • 啟動 Go 程時調用 Add()
  • 在 Go 程結束時調用 Done()
  • 最后調用 Wait()
package main
import ("fmt""sync"
)
func main() {var wg sync.WaitGroupwg.Add(3)go handlerTask1(&wg)go handlerTask2(&wg)go handlerTask3(&wg)wg.Wait()fmt.Println("全部任務執行完畢.")
}
func handlerTask1(wg *sync.WaitGroup) {defer wg.Done()fmt.Println("執行任務 1")
}
func handlerTask2(wg *sync.WaitGroup) {defer wg.Done()fmt.Println("執行任務 2")
}
func handlerTask3(wg *sync.WaitGroup) {defer wg.Done()fmt.Println("執行任務 3")
}

7.sync.Cond

sync.Cond 條件變量用來協調想要訪問共享資源的那些 goroutine,當共享資源的狀態發生變化的時候,它可以用來通知被互斥鎖阻塞的 goroutine。假設一個場景:有一個協程在異步地接收數據,剩下的多個協程必須等待這個協程接收完數據,才能讀取到正確的數據。在這種情況下,如果單純使用 chan 或互斥鎖,那么只能有一個協程可以等待,并讀取到數據,沒辦法通知其他的協程也讀取數據。這個時候,就需要有個全局的變量來標志第一個協程數據是否接受完畢,剩下的協程,反復檢查該變量的值,直到滿足要求。或者創建多個 channel,每個協程阻塞在一個 channel 上,由接收數據的協程在數據接收完畢后,逐個通知。總之,需要額外的復雜度來完成這件事。Go 語言在標準庫 sync 中內置一個sync.Cond 用來解決這類問題。和sync.Cond相關的有4個方法:

  • NewCond創建實例
  • Broadcast廣播喚醒所有
  • Signal喚醒一個協程
  • Wait等待
package main
import ("log""sync""time"
)
var done bool
func main() {// 1. 定義一個互斥鎖,用于保護共享數據mu := sync.Mutex{}// 2. 創建一個sync.Cond對象,關聯這個互斥鎖cond := sync.NewCond(&mu)go read("reader1", cond)go read("reader2", cond)go read("reader3", cond)write("writer", cond)time.Sleep(time.Second * 3)
}
func read(name string, c *sync.Cond) {// 3. 在需要等待條件變量的地方,獲取這個互斥鎖,并使用Wait方法等待條件變量被通知;c.L.Lock()for !done {c.Wait()}log.Println(name, "starts reading")c.L.Unlock()
}
func write(name string, c *sync.Cond) {// 4. 在需要通知等待的協程時,使用Signal或Broadcast方法通知等待的協程。log.Println(name, "starts writing")time.Sleep(time.Second)c.L.Lock()done = truec.L.Unlock()log.Println(name, "wakes all")c.Broadcast() // 如果不廣播, read()方法的 log.Println(name, "starts reading")不會執行
}
/*
輸出:2024/10/02 21:27:50 writer starts writing2024/10/02 21:27:51 writer wakes all2024/10/02 21:27:51 reader3 starts reading2024/10/02 21:27:51 reader1 starts reading2024/10/02 21:27:51 reader2 starts reading
*/

8.sync.Pool

sync.pool用于保存和復用臨時對象,減少內存分配,降低 GC 壓力。使用方式:

  • 聲明對象池
  • Get & Put
package main
import ("encoding/json""fmt""sync"
)
type Student struct {Name string `json:"name"`
}
var studentPool = sync.Pool{New: func() interface{} {return new(Student)},
}
func main() {buf := `{"name":"Mike"}`stu := studentPool.Get().(*Student)fmt.Println(*stu) // {}err := json.Unmarshal([]byte(buf), stu)if err != nil {fmt.Printf("err:%s,err")return}fmt.Println(*stu)studentPool.Put(stu) // {Mike}stu2 := studentPool.Get().(*Student)fmt.Println(*stu2) // {Mike}
}

9.panic和recover

在Go語言中,panic和recover構成了處理程序運行時錯誤的兩個基本機制。它們用于在出現嚴重錯誤時,能夠優雅地終止程序或恢復程序的執行。

  • panic機制
    panic是一個內建函數,用于在程序運行時拋出一個錯誤。當panic被調用時,當前的函數會立即停止執行,并開始逐層向上"冒泡",直到被recover捕獲或到達程序的頂層,導致程序崩潰并輸出錯誤信息。

panic通常用于處理那些無法恢復的錯誤,比如空指針引用、數組越界等。這些錯誤如果不加以處理,將會導致程序崩潰。

  • recover機制
    recover是一個內建函數,用于在defer函數中捕獲由panic拋出的錯誤。當panic發生時,程序會立即停止當前函數的執行,并開始逐層向上查找是否有defer語句。如果在defer函數中調用了recover,那么panic會被捕獲,程序會恢復正常的執行流程,繼續執行defer函數之后的代碼。

需要注意的是,recover只有在defer函數中直接調用時才有效。在其他地方調用recover是無效的,它將返回nil并且不會終止panic。

10.goroutine

在Go語言中,goroutine(Go routine)是一種輕量級的執行單元。可以將其理解為一個函數的并發執行,類似于線程,但比線程更輕量級。與傳統的線程相比,創建和銷毀goroutine的開銷非常小。在Go程序中,可以輕松地創建成千上萬個goroutine,每個goroutine都能夠獨立執行,而不需要手動管理線程和鎖。這使得在Go語言中實現并發變得非常容易。要創建一個goroutine,只需要在函數調用前加上關鍵字"go"即可。Go語言的運行時系統(runtime)負責調度和管理goroutine的執行。運行時系統在多個邏輯處理器上調度goroutine,使得它們可以并發執行。以下是goroutine的底層實現原理的一些關鍵點:

  • 棧的動態增長:每個goroutine有一個固定大小的棧空間,初始大小一般很小(幾KB)。當需要更多的棧空間時,運行時系統會動態地擴展 棧的大小。這種棧的動態增長使得goroutine可以有效地處理深度遞歸或者大型數據結構。
  • 上下文切換:當一個goroutine遇到阻塞操作(如等待I/O、等待通道的數據等)時,運行時系統會自動將該goroutine切換出執行,并讓其他可運行的goroutine繼續執行。這種上下文切換是協作式的,是在運行時系統控制下完成的,而不是由操作系統的調度器決定。這使得goroutine的切換非常高效。
  • 調度器:Go語言的運行時系統有一個調度器(scheduler),負責在邏輯處理器上調度和管理goroutine的執行。調度器會根據一些策略(如工作竊取)來決定將goroutine分配給哪個邏輯處理器執行。調度器還會處理阻塞的goroutine,并在其可以繼續執行時將其重新調度。
  • 垃圾回收:運行時系統中的垃圾回收器(garbage collector)負責自動管理內存的分配和回收。垃圾回收器會追蹤和收集不再使用的對象,并回收其占用的內存空間。垃圾回收器與goroutine的協作非常緊密,確保在回收內存時不會影響正在執行的goroutine。
  • 同步和通信:在多個goroutine之間進行同步和通信通常使用通道(channel)。通道提供了一種安全可靠的方式來傳遞數據和同步操作。通道的使用能夠確保在goroutine之間的數據傳遞和同步操作的正確性和可靠性。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/83409.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/83409.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/83409.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【Unity】相機 Cameras

1 前言 主要介紹官方文檔中相機模塊的內容。 關于“9動態分辨率”,這部分很多API文檔只是提了一下,具體細節還需要自己深入API才行。 2 攝像機介紹 Unity 場景在三維空間中表示游戲對象。由于觀察者的屏幕是二維屏幕,Unity 需要捕捉視圖并將…

SpringBoot(六)--- AOP、ThreadLocal

目錄 前言 一、AOP基礎 1.入門程序 2. AOP核心概念 3. 底層原理 二、AOP進階 1.通知類型 抽取切入點 2. 切入點表達式 2.1 execution 2.2 annoation 2.3 連接點詳解 三、ThreadLocal 前言 AOP(面向切面編程),面向切面編程實際就…

【深度學習】 19. 生成模型:Diffusion Models

Diffusion Models Diffusion Models 簡介 Diffusion 模型是一類通過逐步添加噪聲并再逆向還原的方式進行圖像生成的深度生成模型。其基本流程包括: 前向過程(Forward Process):將真實圖像逐步加噪,最終變為高斯噪聲…

Y1——鏈式前向星

知識點 模版——鏈表的前插法 head表示頭結點的下標 ver[i]表示結點i 的值 tot存儲當前已經用到了哪個 add用于將x插到頭結點 int head1; intt ver[N],Next[N]; int ttot-1; void add(int x){ver[tot]x;Next[tot]head;headtot; } 常見的鏈式前向星三種實現形式&#xff…

如何排查Redis單個Key命中率驟降?

問題現象 Redis整體命中率98%,但監控發現特定Key(如user:1000:profile)的命中率從99%驟降至40%,引發服務延遲上升。 排查步驟 1. 確認現象與定位Key // 通過Redis監控工具獲取Key指標 public void monitorKey(String key) {Je…

自定義Shell命令行解釋器

目錄 1、目標 2、顯示命令提示符 2.1 getenv 2.2 getcwd 2.3 putenv 3、獲取用戶輸入的命令 4、解析命令 5、處理內建命令 6、處理外部命令 7、完整代碼 7.1 myshell.cpp 7.2 Makefile 1、目標 實現一個Linux的myshell,有以下基本的功能。 顯示命令提示…

Laplace 噪聲

Laplace 噪聲是一種特定概率分布(拉普拉斯分布)產生的隨機擾動。它是差分隱私(Differential Privacy, DP)中最核心、最常用的噪聲機制之一。它的核心作用是在不泄露個體信息的前提下,允許從包含敏感數據的數據庫中提取…

基于空天地一體化網絡的通信系統matlab性能分析

目錄 1.引言 2.算法仿真效果演示 3.數據集格式或算法參數簡介 4.MATLAB核心程序 5.算法涉及理論知識概要 5.1 QPSK調制原理 5.2 空天地一體化網絡信道模型 5.3 空天地一體化網絡信道特性 6.參考文獻 7.完整算法代碼文件獲得 1.引言 空天地一體化網絡是一種將衛星通信…

【Delphi】接收windows文件夾中文件拖拽

本文根據EmailX45的視頻文件,進行了優化改進,原文參見:Delphi: Drag and Drop Files from Explorer into TPanel / TMemo - YouTube 在Windows中,如果將選擇的文件拖動到Delphi程序的控件上,有很多實現方法&#xff0c…

基于熱力學熵增原理的EM-GAN

簡介 簡介:提出基于熱力學熵增原理的EM-GAN,通過生成器熵最大化約束增強輸出多樣性。引入熵敏感激活函數與特征空間熵計算模塊,在MNIST/CelebA等數據集上實現FID分數提升23.6%,有效緩解模式崩潰問題。 論文題目:Entropy-Maximized Generative Adversarial Network (EM-G…

HashMap與ConcurrentHashMap詳解:實現原理、源碼分析與最佳實踐

引言 在Java編程中,集合框架是最常用的工具之一,而HashMap和ConcurrentHashMap則是其中使用頻率最高的兩個Map實現。它們都用于存儲鍵值對數據,但在實現機制、性能特點和適用場景上有著顯著差異。 HashMap作為單線程環境下的首選Map實現&am…

CSS之動畫(奔跑的熊、兩面反轉盒子、3D導航欄、旋轉木馬)

一、 2D轉換 1.1 transform: translate( ) 轉換(transform) 是CSS3中具有顛覆性的特征之一,可以實現元素的位移、旋轉、縮放等效果 移動:translate 旋轉:rotate 縮放:scale 下圖為2D轉換的坐標系 回憶…

【筆記】在 MSYS2(MINGW64)中安裝 python-maturin 的記錄

#工作記錄 📌 安裝背景 操作系統:MSYS2 MINGW64當前時間:2025年6月1日Python 版本:3.12(通過 pacman 安裝)目標工具:maturin —— 用于構建和發布 Rust 編寫的 Python 包 🛠? 安裝…

基于微信小程序的垃圾分類系統

博主介紹:java高級開發,從事互聯網行業六年,熟悉各種主流語言,精通java、python、php、爬蟲、web開發,已經做了六年的畢業設計程序開發,開發過上千套畢業設計程序,沒有什么華麗的語言&#xff0…

工作日記之權限校驗-token的實戰案例

背景說明 我們組負責維護的一個系統,前端界面掛載在其他兩個系統上,因為歷史遺留原因,同時也掛在公網上,沒有登陸功能和用戶體系,只要輸入網址就能訪問,雖然這個系統是給公司內部人員使用,但是…

mysql雙主模式下基于keepalived的虛擬ip實現高可用模式搭建

數據庫安裝和升級和雙主配置的操作可以參考我的另一篇文章: 數據庫安裝和升級和雙主配置 1、在兩臺服務器都下載和安裝keepalived 下載: yumdownloader --resolve keepalived 下載后得到: [rootlocalhost keepalivedRpm]# ll 總用量 1896 …

展會聚焦丨漫途科技亮相2025西北水務博覽會!

2025第三屆西北水務數字化發展論壇暨供排水節水灌溉新技術設備博覽會在蘭州甘肅國際會展中心圓滿落幕。本屆展會以“科技賦能水資源,數智引領新動能”為主題,活動匯集水務集團、科研院所、技術供應商等全產業鏈參與者,旨在通過前沿技術展示與…

單調棧(打卡)

本篇基于b站靈茶山艾府。 下面是靈神上課講解的題目與課后作業,課后作業還有三道實在寫不下去了,下次再寫。 739. 每日溫度 給定一個整數數組 temperatures ,表示每天的溫度,返回一個數組 answer ,其中 answer[i] 是…

【機器學習基礎】機器學習入門核心算法:層次聚類算法(AGNES算法和 DIANA算法)

機器學習入門核心算法:層次聚類算法(AGNES算法和 DIANA算法) 一、算法邏輯二、算法原理與數學推導1. 距離度量2. 簇間距離計算(連接標準)3. 算法偽代碼(凝聚式) 三、模型評估1. 內部評估指標2. …

已有的前端項目打包到tauri運行(windows)

1.打包前端項目產生靜態html、css、js 我們接下來用vue3 vite編寫一個番茄鐘案例來演示。 我們執行npm run build 命令產生的dist目錄下的靜態文件。 2.創建tarui項目 npm create tauri-applatest一路回車,直到出現。 3.啟動運行 我們將打包產生的dist目錄下的…