linux 國(guó)外網(wǎng)站網(wǎng)站建設(shè)蘇州
什么協(xié)程
在Go語(yǔ)言中,協(xié)程就是一種輕量的線(xiàn)程,是并發(fā)編程的單元,由Go來(lái)管理,所以在GO層面的協(xié)程會(huì)更加的輕量、高效、開(kāi)銷(xiāo)更小,并且更容易實(shí)現(xiàn)并發(fā)編程。
輕量級(jí)線(xiàn)程
- Go語(yǔ)言中協(xié)程(線(xiàn)程)與傳統(tǒng)系統(tǒng)層面的線(xiàn)程相比,實(shí)在是太輕量了,能小到2kb
- 由于協(xié)程的輕量特性,可以更高效地利用系統(tǒng)資源。相較于傳統(tǒng)的線(xiàn)程,協(xié)程的創(chuàng)建和銷(xiāo)毀的開(kāi)銷(xiāo)更小,使得程序更具有擴(kuò)展性和性能優(yōu)勢(shì)。
Go自身管理
- 在 Go 中,這些工作由運(yùn)行時(shí)系統(tǒng)自動(dòng)完成。這樣我們就可以更專(zhuān)注于業(yè)務(wù)邏輯,而不必過(guò)多關(guān)心底層線(xiàn)程管理的細(xì)節(jié)。
并發(fā)的基本單元
- 協(xié)程是并發(fā)編程的基本單元,可以同時(shí)執(zhí)行多個(gè)協(xié)程,而它們之間的調(diào)度和切換由運(yùn)行時(shí)系統(tǒng)負(fù)責(zé)。
- 在程序中更容易實(shí)現(xiàn)高效的并發(fā),處理多個(gè)任務(wù)而無(wú)需顯式地創(chuàng)建和管理線(xiàn)程。
- 使用協(xié)程,我們可以輕松地實(shí)現(xiàn)并發(fā)任務(wù),例如同時(shí)處理多個(gè)網(wǎng)絡(luò)請(qǐng)求、執(zhí)行后臺(tái)任務(wù)等。由于協(xié)程的輕量特性,可以創(chuàng)建數(shù)千甚至數(shù)百萬(wàn)個(gè)協(xié)程而不會(huì)造成系統(tǒng)負(fù)擔(dān)。
使用通道通信
- 協(xié)程之間可以通過(guò)通道進(jìn)行通信,這是一種在協(xié)程之間安全地傳遞數(shù)據(jù)和同步操作的機(jī)制。通道是一種強(qiáng)大的工具,用于協(xié)程之間的協(xié)作和數(shù)據(jù)傳遞。
協(xié)程的基本操作
創(chuàng)建協(xié)程
- 語(yǔ)法: `go 函數(shù)(函數(shù)列表)`
package main import ( "fmt" "time") func Hello() { fmt.Println("hello world")
} func main() { go Hello() fmt.Println("hello main") time.Sleep(10 * time.Second)
}
協(xié)程與主線(xiàn)程是并發(fā)執(zhí)行的。
協(xié)程間通行
- 主要通過(guò)
channel
來(lái)實(shí)現(xiàn)的
package main import ( "fmt"
) func sendMessage(ch chan string, msg string) { ch <- msg
} func main() { messagechan := make(chan string) go sendMessage(messagechan, "Hello World") msg := <-messagechan fmt.Println(msg)
}
協(xié)程間的同步
- 使用sync包來(lái)實(shí)現(xiàn)的
- waitgroup 是用來(lái)計(jì)數(shù)信號(hào)量的
package main import ( "fmt" "sync") func worker(id int, wg *sync.WaitGroup) { defer wg.Done() fmt.Printf("worker %d starting\n", id) fmt.Printf("worker %d done\n", id)
} func main() { var wg sync.WaitGroup for i := 1; i <= 10; i++ { wg.Add(1) go worker(i, &wg) } wg.Wait() fmt.Printf("all workers done\n")
}
waitgroup確保主線(xiàn)程等待所有協(xié)程完成
協(xié)程的錯(cuò)誤處理
- 使用
select
語(yǔ)句和通道可以實(shí)現(xiàn)協(xié)程的錯(cuò)誤處理
package main import ( "fmt" "time") func dosomething(ch chan string) { time.Sleep(2 * time.Second) ch <- "hello world"
} func main() { ch := make(chan string) go dosomething(ch) select { case msg := <-ch: fmt.Println(msg) case <-time.After(1 * time.Second): fmt.Println("timeout") }
}
select
?語(yǔ)句允許在多個(gè)通道操作中選擇一個(gè)可用的操作,可以用來(lái)處理協(xié)程的超時(shí)等情況。
協(xié)程的高級(jí)操作
協(xié)程池
- 協(xié)程池是一組預(yù)先創(chuàng)建的協(xié)程,用于執(zhí)行并發(fā)任務(wù),可以避免頻繁創(chuàng)建和銷(xiāo)毀協(xié)程的開(kāi)銷(xiāo)。
- 使用緩沖通道來(lái)實(shí)現(xiàn)協(xié)程池
package main import ( "fmt" "sync") func worker(id int, jobs <-chan int, results chan<- int) { for j := range jobs { fmt.Println("worker", id, "started job", j) results <- j * 2 }
} func main() { const numJobs = 5 const numWorkers = 3 jobs := make(chan int, numJobs) results := make(chan int, numJobs) var wg sync.WaitGroup for i := 1; i <= numWorkers; i++ { wg.Add(1) go func(i int) { defer wg.Done() worker(i, jobs, results) }(i) } for j := 1; j <= 5; j++ { jobs <- j } close(jobs) go func() { wg.Wait() close(results) }() for result := range results { fmt.Println("result", result) }
}
三個(gè)協(xié)程形成了協(xié)程池,從任務(wù)通道?
jobs
?中獲取任務(wù),處理后將結(jié)果發(fā)送到結(jié)果通道?results
超時(shí)控制
package main import ( "fmt" "time") func dosomething(ch chan string) { time.Sleep(2 * time.Second) ch <- "hello world"
} func main() { ch := make(chan string) go dosomething(ch) select { case msg := <-ch: fmt.Println(msg) case <-time.After(1 * time.Second): fmt.Println("timeout") }
}
time.After
?創(chuàng)建一個(gè)計(jì)時(shí)器,如果在指定時(shí)間內(nèi)沒(méi)有從通道?ch
?中接收到結(jié)果,就會(huì)觸發(fā)超時(shí)。
協(xié)程的取消
- 使用?
context
?包提供的上下文(Context)來(lái)實(shí)現(xiàn)協(xié)程的取消。
package main import ( "context" "fmt" "time") func doSomething(ctx context.Context, ch chan string) { select { case <-ctx.Done(): ch <- "task completed successfully" case <-time.After(1 * time.Second): ch <- "task timed out" }
} func main() { ctx, cancel := context.WithCancel(context.Background()) defer cancel() ch := make(chan string) go doSomething(ctx, ch) time.Sleep(2 * time.Second) cancel() result := <-ch fmt.Println(result)
}
通過(guò)調(diào)用?
cancel
?函數(shù)取消協(xié)程的執(zhí)行。