Go語(yǔ)言使用Goroutine并發(fā)打印的項(xiàng)目實(shí)踐
在本篇文章中,我們將從最基礎(chǔ)的 Goroutine 并發(fā)模型入手,逐步掌握 Go 語(yǔ)言中并發(fā)控制的核心思想。通過(guò)一個(gè)簡(jiǎn)單的“并發(fā)打印任務(wù)”案例,掌握 Goroutine 的使用、輸出順序的控制、主協(xié)程退出時(shí)機(jī)等關(guān)鍵知識(shí)。
一、為什么學(xué)習(xí) Goroutine?
Goroutine 是 Go 語(yǔ)言最核心的并發(fā)原語(yǔ)。相比于線程,它更加輕量:
- 啟動(dòng)成本極低(大約只需 2KB 內(nèi)存)
- 數(shù)量可以輕松達(dá)到上萬(wàn)甚至百萬(wàn)級(jí)
- 使用非常簡(jiǎn)單,只需一個(gè)
go關(guān)鍵字
Go 的并發(fā)理念是:不要通過(guò)共享內(nèi)存來(lái)通信,而要通過(guò)通信來(lái)共享內(nèi)存。
掌握 Goroutine,是理解 Go 并發(fā)模型的第一步。
二、實(shí)戰(zhàn)目標(biāo)
我們將實(shí)現(xiàn)一個(gè)小項(xiàng)目:
- 啟動(dòng)多個(gè) Goroutine 并發(fā)打印任務(wù)信息
- 每個(gè)任務(wù)打印固定內(nèi)容
- 確保主程序等待所有任務(wù)完成
- 引入
sync.WaitGroup實(shí)現(xiàn)同步控制
三、基礎(chǔ)版本:?jiǎn)?dòng)多個(gè) Goroutine
下面是最簡(jiǎn)單的 Goroutine 并發(fā)打印實(shí)現(xiàn):
package main
import (
"fmt"
"time"
)
func printTask(id int) {
fmt.Printf("任務(wù) %d 正在執(zhí)行\(zhòng)n", id)
}
func main() {
for i := 1; i <= 5; i++ {
go printTask(i)
}
// 給協(xié)程一點(diǎn)時(shí)間完成(不推薦的方式)
time.Sleep(time.Second)
fmt.Println("主程序結(jié)束")
}
運(yùn)行結(jié)果(示例):
任務(wù) 2 正在執(zhí)行
任務(wù) 4 正在執(zhí)行
任務(wù) 1 正在執(zhí)行
任務(wù) 3 正在執(zhí)行
任務(wù) 5 正在執(zhí)行
主程序結(jié)束
你會(huì)注意到,輸出順序可能與代碼中的順序不同,這是并發(fā)執(zhí)行的結(jié)果。
四、問(wèn)題:主程序過(guò)早退出
在上面例子中我們使用了 time.Sleep 來(lái)“湊時(shí)間”,這是一種不可靠且危險(xiǎn)的方式。如果任務(wù)執(zhí)行時(shí)間更長(zhǎng),就會(huì)被主程序強(qiáng)制退出。
為了解決這個(gè)問(wèn)題,我們引入 sync.WaitGroup。
五、進(jìn)階版本:使用 WaitGroup 等待所有 Goroutine 完成
package main
import (
"fmt"
"sync"
"time"
)
// 模擬執(zhí)行任務(wù)
func printTask(id int, wg *sync.WaitGroup) {
defer wg.Done() // 標(biāo)記一個(gè)任務(wù)完成
fmt.Printf("任務(wù) %d 開始執(zhí)行\(zhòng)n", id)
time.Sleep(time.Duration(id) * 200 * time.Millisecond) // 模擬不同任務(wù)耗時(shí)
fmt.Printf("任務(wù) %d 執(zhí)行完畢\n", id)
}
func main() {
var wg sync.WaitGroup
taskCount := 5
for i := 1; i <= taskCount; i++ {
wg.Add(1) // 增加一個(gè)任務(wù)
go printTask(i, &wg)
}
wg.Wait() // 等待所有任務(wù)完成
fmt.Println("所有任務(wù)完成,主程序退出")
}
輸出示例:
任務(wù) 1 開始執(zhí)行
任務(wù) 2 開始執(zhí)行
任務(wù) 3 開始執(zhí)行
任務(wù) 4 開始執(zhí)行
任務(wù) 5 開始執(zhí)行
任務(wù) 1 執(zhí)行完畢
任務(wù) 2 執(zhí)行完畢
任務(wù) 3 執(zhí)行完畢
任務(wù) 4 執(zhí)行完畢
任務(wù) 5 執(zhí)行完畢
所有任務(wù)完成,主程序退出
六、重點(diǎn)知識(shí)點(diǎn)解析
1.go關(guān)鍵字
只需在函數(shù)前加 go,即可將該函數(shù)交由調(diào)度器異步執(zhí)行,立即返回。
2.sync.WaitGroup
wg.Add(n):添加 n 個(gè)任務(wù)wg.Done():在任務(wù)完成后調(diào)用wg.Wait():阻塞主線程,直到所有任務(wù)完成
3.defer用法
使用 defer wg.Done() 可以確保即使函數(shù)中途返回也能正確減計(jì)數(shù)。
七、延伸思考
- 若有 10萬(wàn)個(gè)任務(wù)要并發(fā)執(zhí)行,Goroutine 是否能承載?(答案是:可以,但建議使用并發(fā)控制池)
- 如果某個(gè)任務(wù)失敗,是否能提前取消其他任務(wù)?(答案是:可以結(jié)合
context實(shí)現(xiàn))
八、真實(shí)應(yīng)用場(chǎng)景舉例
- 批量調(diào)用多個(gè)接口(如:并發(fā)請(qǐng)求天氣接口、發(fā)郵件)
- 批量處理文件(壓縮、上傳、轉(zhuǎn)碼)
- 并發(fā)爬蟲(抓取多個(gè)頁(yè)面)
- 消息隊(duì)列并發(fā)消費(fèi)任務(wù)
九、小結(jié)
本文通過(guò)“并發(fā)打印任務(wù)”這一簡(jiǎn)單示例,向你展示了 Go 并發(fā)編程的基本能力:
- 啟動(dòng) Goroutine 的方法
- 并發(fā)任務(wù)間的非確定性
- 如何使用 WaitGroup 來(lái)保證主程序的正確退出
- Goroutine 的輕量特性,適合高并發(fā)場(chǎng)景
并發(fā)是 Go 的靈魂,控制好協(xié)程的生命周期和調(diào)度能力,將直接影響系統(tǒng)的健壯性與性能。
到此這篇關(guān)于Go語(yǔ)言使用Goroutine并發(fā)打印的項(xiàng)目實(shí)踐的文章就介紹到這了,更多相關(guān)Go Goroutine并發(fā)打印內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- golang gin 框架 異步同步 goroutine 并發(fā)操作
- Go語(yǔ)言中的并發(fā)goroutine底層原理
- Go并發(fā)編程之goroutine使用正確方法
- Go 并發(fā)編程Goroutine的實(shí)現(xiàn)示例
- Golang 語(yǔ)言控制并發(fā) Goroutine的方法
- golang并發(fā)編程中Goroutine 協(xié)程的實(shí)現(xiàn)
- Go中Goroutines輕量級(jí)并發(fā)的特性及效率探究
- 使用Go?goroutine實(shí)現(xiàn)并發(fā)的Clock服務(wù)
- Go語(yǔ)言使用goroutine及通道實(shí)現(xiàn)并發(fā)詳解
- Go 控制協(xié)程(goroutine)的并發(fā)數(shù)量
相關(guān)文章
go語(yǔ)言制作一個(gè)gif動(dòng)態(tài)圖
這篇文章主要介紹了go制作一個(gè)gif動(dòng)態(tài)圖的相關(guān)資料,需要的朋友可以參考下2015-03-03
Go?并發(fā)編程協(xié)程及調(diào)度機(jī)制詳情
這篇文章主要介紹了Go并發(fā)編程協(xié)程及調(diào)度機(jī)制詳情,協(xié)程是Go語(yǔ)言最大的特色之一,goroutine的實(shí)現(xiàn)其實(shí)是通過(guò)協(xié)程,更多相關(guān)內(nèi)容需要的朋友可以參考一下2022-09-09
Go語(yǔ)言實(shí)現(xiàn)JSON解析的方法詳解
在日常項(xiàng)目中,使用Json格式進(jìn)行數(shù)據(jù)封裝是比較常見的操作。本文將詳細(xì)講解如何利用Go語(yǔ)言實(shí)現(xiàn)JSON的解析,感興趣的小伙伴可以學(xué)習(xí)一下2022-04-04

