Go 中的並發:從基礎知識到高階概念
目錄
- 並發簡介
- 併發與並行
- Go 程式:並發的建構塊
- 通道:Go 程式之間的通訊
- Select 語句:管理多個通道
- 同步原語
- 並發模式
- 上下文包:管理取消和 超時。
- 最佳實務與常見陷阱**
1.並發簡介
並發是同時處理多個任務的能力。在 Go 中,並發性是一等公民,內建於該語言的核心設計中。 Go 的並發方法是基於通訊順序進程(CSP),該模型強調進程之間的通訊而不是共享記憶體。
2.併發與並行:
Go 例程支援並發,並發是獨立執行進程的組合。
如果系統有多個 CPU 核心並且 Go 運行時安排 go 例程並行運行,則可能會發生並行(同時執行)。
3。 Go 例程:
並發的構建塊是 Go 例程是由 Go 運行時管理的輕量級執行緒。它是與其他函數或方法同時運行的函數或方法。 Go 例程是 Go 並發模型的基礎。
主要特徵:
- 輕量級:Go 例程比作業系統執行緒輕得多。您可以輕鬆建立數千個 go 例程,而不會顯著影響效能。
- 由 Go 執行時期管理:Go 排程器處理可用作業系統執行緒之間的 go 例程指派。
- 廉價建立:啟動 go 例程就像在函數呼叫之前使用 go 關鍵字一樣簡單。
- 堆疊大小:Go 程式從一個小堆疊(大約 2KB)開始,可以根據需要增長和縮小。
建立 Go 程式:
要啟動 go 例程,只需使用 go 關鍵字,後面接著函數呼叫:
go functionName()
或使用匿名函數:
go func() { // function body }()
Go-routine 調度:
- Go 運行時使用 M:N 調度程序,其中 M 個 go 例程被調度到 N 個作業系統執行緒上。
- 這個調度程序是非搶佔式的,這意味著 Go 例程在空閒或邏輯阻塞時會產生控制權。
通訊與同步:
- Goroutine 通常使用通道進行通信,遵循「不要透過共享記憶體進行通信;透過通信來共享記憶體」的原則。
- 對於簡單的同步,您可以使用像sync.WaitGroup或sync.Mutex這樣的原語。
範例及說明:
package main import ( "fmt" "time" ) func printNumbers() { for i := 1; i <= 5; i++ { time.Sleep(100 * time.Millisecond) fmt.Printf("%d ", i) } } func printLetters() { for i := 'a'; i <= 'e'; i++ { time.Sleep(150 * time.Millisecond) fmt.Printf("%c ", i) } } func main() { go printNumbers() go printLetters() time.Sleep(2 * time.Second) fmt.Println("\nMain function finished") }
說明:
- 我們定義了兩個函數:printNumbers 和 printLetters。
- 在 main 中,我們使用 go 關鍵字將這些函數作為 goroutine 啟動。
- 然後 main 函數休眠 2 秒,讓 goroutine 完成。
- 如果沒有 goroutine,這些函數將按順序運行。對於 goroutine,它們是同時運行的。
- 輸出將顯示數字和字母交錯,並示範並發執行。
Goroutine 生命週期:
- goroutine 在使用 go 關鍵字建立時啟動。
- 當其功能完成或程式退出時,它終止。
- 如果管理不當,Goroutines 可能會洩漏,因此確保它們可以退出非常重要。
最佳實務:
- 不要在庫中建立 goroutine;讓呼叫者控制並發。
- 創建無限數量的 goroutine 時要小心。
- 使用通道或同步原語在 goroutine 之間進行協調。
- 考慮使用工作池來有效管理多個 goroutine。
帶有 go 程式解釋的簡單範例
package main import ( "fmt" "time" ) // printNumbers is a function that prints numbers from 1 to 5 // It will be run as a goroutine func printNumbers() { for i := 1; i <= 5; i++ { time.Sleep(500 * time.Millisecond) // Sleep for 500ms to simulate work fmt.Printf("%d ", i) } } // printLetters is a function that prints letters from 'a' to 'e' // It will also be run as a goroutine func printLetters() { for i := 'a'; i <= 'e'; i++ { time.Sleep(300 * time.Millisecond) // Sleep for 300ms to simulate work fmt.Printf("%c ", i) } } func main() { // Start printNumbers as a goroutine // The 'go' keyword before the function call creates a new goroutine go printNumbers() // Start printLetters as another goroutine go printLetters() // Sleep for 3 seconds to allow goroutines to finish // This is a simple way to wait, but not ideal for production code time.Sleep(3 * time.Second) // Print a newline for better formatting fmt.Println("\nMain function finished") }
4.頻道:
通道是 Go 中的一項核心功能,它允許 go 例程相互通訊並同步執行。它們為一個 go 例程提供了一種將資料傳送到另一個 go 例程的方法。
頻道的目的
Go 中的通道有兩個主要用途:
a) 通訊:它們允許 goroutine 相互發送和接收值。
b) 同步:它們可用於跨 Goroutine 同步執行。
建立:使用 make 函數建立通道:
ch := make(chan int) // Unbuffered channel of integers
傳送:使用
ch <- 42 // Send the value 42 to the channel
Receiving: Values are received from a channel using the <- operator:
value := <-ch // Receive a value from the channel
Types of Channels
a) Unbuffered Channels:
- Created without a capacity: ch := make(chan int)
- Sending blocks until another goroutine receives.
- Receiving blocks until another goroutine sends.
ch := make(chan int) go func() { ch <- 42 // This will block until the value is received }() value := <-ch // This will receive the value
b) Buffered Channels:
- Created with a capacity: ch := make(chan int, 3)
- Sending only blocks when the buffer is full.
- Receiving only blocks when the buffer is empty.
ch := make(chan int, 2) ch <- 1 // Doesn't block ch <- 2 // Doesn't block ch <- 3 // This will block until a value is received
Channel Directions
Channels can be directional or bidirectional:
- Bidirectional: chan T
- Send-only: chan<- T
- Receive-only: <-chan T
Example :
func send(ch chan<- int) { ch <- 42 } func receive(ch <-chan int) { value := <-ch fmt.Println(value) }
Closing Channels
Channels can be closed to signal that no more values will be sent:
close(ch)
Receiving from a closed channel:
If the channel is empty, it returns the zero value of the channel's type.
You can check if a channel is closed using a two-value receive:
value, ok := <-ch if !ok { fmt.Println("Channel is closed") }
Ranging over Channels
You can use a for range loop to receive values from a channel until it's closed:
for value := range ch { fmt.Println(value) }
Hey, Thank you for staying until the end! I appreciate you being valuable reader and learner. Please follow me here and also on my Linkedin and GitHub .
以上是Go 中的並發:從基礎知識到高階概念的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

OpenSSL,作為廣泛應用於安全通信的開源庫,提供了加密算法、密鑰和證書管理等功能。然而,其歷史版本中存在一些已知安全漏洞,其中一些危害極大。本文將重點介紹Debian系統中OpenSSL的常見漏洞及應對措施。 DebianOpenSSL已知漏洞:OpenSSL曾出現過多個嚴重漏洞,例如:心臟出血漏洞(CVE-2014-0160):該漏洞影響OpenSSL1.0.1至1.0.1f以及1.0.2至1.0.2beta版本。攻擊者可利用此漏洞未經授權讀取服務器上的敏感信息,包括加密密鑰等。

在BeegoORM框架下,如何指定模型關聯的數據庫?許多Beego項目需要同時操作多個數據庫。當使用Beego...

後端學習路徑:從前端轉型到後端的探索之旅作為一名從前端開發轉型的後端初學者,你已經有了nodejs的基礎,...

Go語言中使用RedisStream實現消息隊列時類型轉換問題在使用Go語言與Redis...

GoLand中自定義結構體標籤不顯示怎麼辦?在使用GoLand進行Go語言開發時,很多開發者會遇到自定義結構體標籤在�...

Go語言中用於浮點數運算的庫介紹在Go語言(也稱為Golang)中,進行浮點數的加減乘除運算時,如何確保精度是�...

Go爬蟲Colly中的Queue線程問題探討在使用Go語言的Colly爬蟲庫時,開發者常常會遇到關於線程和請求隊列的問題。 �...

本文介紹如何在Debian系統上配置MongoDB實現自動擴容,主要步驟包括MongoDB副本集的設置和磁盤空間監控。一、MongoDB安裝首先,確保已在Debian系統上安裝MongoDB。使用以下命令安裝:sudoaptupdatesudoaptinstall-ymongodb-org二、配置MongoDB副本集MongoDB副本集確保高可用性和數據冗餘,是實現自動擴容的基礎。啟動MongoDB服務:sudosystemctlstartmongodsudosys
