Go併發模型
隔離(Confinedent)
在 Go 程式中透過程式碼慣例(而非語言機制)來保證某個資源(變數或物件)只會在某個 goroutine 中被存取
假設你有一個data []byte
,你需要將它傳給某個函數去讀裡面的資料(read only),但是它又沒有像io.Reader或<-chan這樣的只讀寫法。這時候,只需將它隔離起來即可:
func ReadOnly[T any](data []T) <-chan T {
dataCh := make(chan T)
go func() {
defer close(dataCh)
for _, d := range data {
dataCh <- d
}
}()
return dataCh
}
func main() {
sourceData := make([]int, 100) // [0,0,0...0]
for i, d := range sourceData {
fmt.Println(d)
sourceData[i] = 1 // 在讀取 sourceData 時發生了寫入,危險!
}
for d := range ReadOnly(sourceData) {
fmt.Println(d)
}
}
但是當在for range readOnly(sourceData)
的時候如果中途break或return,在另一個協程中還在嘗試向dataCh中不斷寫入資料,此時會發生goroutine洩漏。為了防止以上情況,我們可以引入context
讓我們在reader協程中途退出時出發cancel context,讓writer協程也能順利退出。
func ReadOnlyWithContext[T any](ctx context.Context, data []T) <-chan T {
dataCh := make(chan T)
go func() {
defer close(dataCh)
for _, d := range data {
select {
case <-ctx.Done():
return
case dataCh <- d:
}
}
}()
return dataCh
}
func main() {
sourceData := make([]int, 100) // [0,0,0...0]
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
count := 0
for d := range ReadOnlyWithContext(ctx, sourceData) {
if count > 50 {
cancel() //在退出時發出 cancel 信號
break
}
fmt.Println(count, ":", d)
count++
}
}
取消(Cancellation)
有時,我們可以不通過context來提前終止程式,而是通過chan。
從零開始發佈 Go 專案到 GitHub
建立 GitHub 專案
-> 產生遠端 repo:https://github.com/你的帳號/你的專案.git
在本地 clone
注意使用SSH:
git clone git@github.com:你的帳號/你的專案.git
cd ppap-demo
建立 go.mod
go mod init github.com/你的帳號/你的專案
新增你的原始碼檔案
touch demo.go
編輯內容:
package ppapdemo
func Demo() string {
return ""
}
git 提交與推送
git add .
git commit -m "新增初始程式碼"
git push