GoLang - Goroutine (上) 基本原理與結構
在這幾篇,會以 Go 語言的入門基礎進行逐步說明,本篇針對 goroutine 進行說明
goroutine 與 thread 差異
在 Go 語言中,goroutine 非常類似於執行緒,他運行的方式是透過多工的方式並行,本質上一個 goroutine 是單執行緒,而 thread 屬多執行緒,每個執行緒之間屬於同步機制,同時運行是以經典搶佔多工方式運作。
簡單來說,10 幾個 goroutine 運作的底層只有 5 個 thread。
在 goroutine 與其他語言的 coroutine 相似,在運行過程只需要少量的記憶體用量(4k~5k),擁有自己的上下文,以及暫存這些上下文,可以在不同時間點分段執行任務。
在 Go 語言另外針對 goroutine 實作了 goroutine 之間的記憶體共用機制,並且設計了 channel 讓 goroutine 之間可以進行資料溝通。
但是,實際設計平行處理時,要謹記!不要透過共用記憶體機制,而是要透過 channel 來進行通訊
在 Go 語言包含了 runtime 這個 package, runtime 的 operations 的方法中,就包含控制 goroutines 的 functions。
只要透過 go
CVT2HUGO: 關鍵字就可以啟動 ```goroutine```,查看以下範例:
package main
import (
"fmt"
"runtime"
)
func showData(txt string) {
fmt.Println("==>", txt)
}
func main() {
go showData("hi")
showData("all")
}
Environment variables
這裡先介紹一些 runtime 的環境變數,針對 Environment variables 後續再進行詳細的介紹:
GOGC: 可以用來設定垃圾回收(garbage collection)的百分比,預設為 100,可以設定為 off 表示關閉回收機制。
SetGCPercent( ): 可以透過這個函數來設定 GOGC 的值。
GODEBUG: 控制 runtime 的 debugging variable ,可以透過 name=value, name=value, … 的方式設定,主要的 name 包含有以下幾種,在 net, net/http, 與 crypto/tls 也有參考到 debugging variables,詳細的用法建議可參考這裡
allocfreetrace
clobberfree
cgocheck
efence
gccheckmark
gcpacertrace
gcshrinkstackoff
gcstoptheworld
gctrace
madvdontneed
memprofilerate
invalidptr
sbrk
scavenge
scavtrace
scheddetail
schedtrace
tracebackancestors
asyncpreemptoff
GOMAXPROCS(n): 可以設定可執行的CPU核心,限制同時在 user-level 的 threads 的數量
GORACE( ) : 可以用來控制 race detector ,在兩個goroutines 訪問同一個 variable 產生 data race 時的作法,細節可參考這裡
GOTRACEBACK( ): 當 go 運作失敗時,可以控制 output 的內容
Goexit( ): 可以退出目前的 goroutine ,退出前會觸發 defer
Goshed( ): 可以將目前 gorotuine 使用的CPU時間切片讓給其他 goroutine,並且不會暫停,等有空閒的CPU切片時,再接續進行
NumCPU( ): 可以取得目前CPU的核心數
NumGoroutine( ): 可以回傳目前正在運行的 goroutines 數量
下方舉個例子, 先執行一個正常呼叫函數的流程:
package main
import (
"fmt"
"runtime"
)
func showData(txt string) {
for i := 0; i < 5; i++ {
runtime.Gosched()
fmt.Println("RealOutput==>", txt)
}
}
func main() {
fmt.Println("stage 1")
showData("hi")
fmt.Println("stage 2")
showData("all")
fmt.Println("stage 3")
}
output
stage 1
RealOutput==> hi
RealOutput==> hi
RealOutput==> hi
RealOutput==> hi
RealOutput==> hi
stage 2
RealOutput==> all
RealOutput==> all
RealOutput==> all
RealOutput==> all
RealOutput==> all
stage 3
接著,將第一個呼叫函示的方式用 goroutines 方式
package main
import (
"fmt"
"runtime"
)
func showData(txt string) {
for i := 0; i < 5; i++ {
runtime.Gosched()
fmt.Println("RealOutput==>", txt)
}
}
func main() {
fmt.Println("stage 1")
go showData("hi")
fmt.Println("stage 2")
showData("all")
fmt.Println("stage 3")
}
output
stage 1
stage 2
RealOutput==> all
RealOutput==> all
RealOutput==> all
RealOutput==> all
RealOutput==> all
stage 3
RealOutput==> hi
RealOutput==> hi
RealOutput==> hi