goroutine 是 Go 語言實現併發的一種方式,在執行的過程需要少量的記憶體用量(4k~5k),以暫存自己的上下文,可在不同的時間點來分段執行程式。而 Go 語言也實作了 goroutine 之間的記憶體共用機制,並且設計了 channel 讓 goroutine 之間可以進行資料溝通。
Go 語言在使用 goroutine 上非常簡單,只要函式前加個 go 即可。我們用 Go Tutorial 上的例子,然後先改編一下,試試看不要加 time.Sleep 看看(程式碼執行到 time.Sleep 時,會停頓指定的時間)。
package main
import (
"fmt"
)
func say(s string) {
for i := 0; i < 5; i++ {
fmt.Println(s)
}
}
func main() {
go say("world")
say("hello")
}
在執行程式碼後,會發現 goroutine 後的程式碼並沒有執行,這是因為你的主程式並沒有等你的 goroutine 執行,就結束掉了,所以我們必須要讓程式停頓一下,讓他可以執行 goroutine :
package main
import (
"fmt"
"time"
)
func say(s string) {
for i := 0; i < 5; i++ {
time.Sleep(100 * time.Millisecond)
fmt.Println(s)
}
}
func main() {
go say("world")
say("hello")
}
在上一個例子,我們用讓程式碼睡一下的方法,使得併發得以實現,但在實務上,比較少直接使用這個方法,這裏要介紹另外一個方法,是使用 sync 套件裡的方法 WaitGroup,來實現併發:
package main
import (
"fmt"
"sync"
)
var wg sync.WaitGroup
func count(s string) {
fmt.Println(s)
wg.Done()
}
func main() {
wg.Add(5)
go count("1")
go count("2")
go count("3")
go count("4")
go count("5")
wg.Wait()
}
我們來解以上的程式碼,在程式碼尾端加上wg.Wait(),讓他達成一些條件,才可以往後執行,而這個條件,就是收到wg.Done()的呼叫次數,而這個次數,即是wg.Add(5)裡的數字5,取決於你要執行幾個 goroutine,請確保這個數字要正確。
這裡要介紹 goroutine 與 channel 的搭配,channel 實現了 goroutine 之間進行資料溝通,而因為也有阻塞的特性,使其可以當作等待 goroutine 的方法,這也算是最平凡的用法之一,goroutine 與 channel 真的是 Go 語言妙的設計之一。
package main
import (
"fmt"
"time"
)
func say(s string, c chan string) {
for i := 0; i < 5; i++ {
time.Sleep(time.Second)
fmt.Println(s)
}
c <- "FINISH"
}
func main() {
ch := make(chan string)
go say("world", ch)
go say("hello", ch)
<-ch
<-ch
}
這裡起了兩個 goroutine,因此需要等待兩個 FINISH 推入 channel 中才能結束主程式的 goroutine。
今天介紹了基本 goroutine 的使用方法,讀者們可以試著執行或是改編看看。而 goroutine 及 channel 簡單而強大的語法,使工程師便於開發又易於維護,是 Go 語言的優勢之一。感謝您今天的閱讀,希望有幫助到您!