Go的并發
有的地方稱為協程
Go 語言可以通過 go 關鍵字來開啟 goroutine 即可實作多執行緒的并發任務處理,
goroutine 是輕量級執行緒,goroutine 的調度是由 Golang 運行時進行管理的,
- 我們通過這一個實體認識一下:
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")
}
在運行結果中,hello和word是隨機出現的,說明并發模式下執行的陳述句沒有先后順序,并且每次運行的結果都是不同的
通道(channel)
通道(channel)是用來傳遞資料的一個資料結構,
- 通道可用于兩個 goroutine 之間通過傳遞一個指定型別的值來同步運行和通訊,
- 運算子 <- 用于指定通道的方向,發送或接收,
- 如果未指定方向,則為雙向通道,
ch <- v// 把 v 發送到通道 ch
v := <-ch// 從 ch 接收資料 、并把值賦給 v
創建一個’通道’可以使用關鍵字chan,并且在使用前必須創建
一個實體:
package main
import "fmt"
func sum(s []int, c chan int) {
sum := 0
for _, v := range s {
sum += v
}
c <- sum // 把 sum 發送到通道 c
}
func main() {
s := []int{7, 2, 8, -9, 4, 0}
c := make(chan int)
go sum(s[:len(s)/2], c)
go sum(s[len(s)/2:], c)
x, y := <-c, <-c // 從通道 c 中接收
fmt.Println(x, y, x+y)
}
這段代碼的效果是通過兩個 goroutine 來計算數字之和,在 goroutine 完成計算后,它會計算兩個結果的和
緩沖信道(Buffer Channels)
我們可以創建一個有緩沖(Buffer)的信道,只在緩沖已滿的情況,才會阻塞向緩沖信道(Buffered Channel)發送資料,同樣,只有在緩沖為空的時候,才會阻塞從緩沖信道接收資料,
- 通過向 make 函式再傳遞一個表示容量的引數(指定緩沖的大小),可以創建緩沖信道,
ch := make(chan type, capacity)
- 要讓一個信道有緩沖, capacity(容量) 應該大于 0,無緩沖信道的容量默認為 0,
這個例子創建了一個緩沖信道,
package main
import (
"fmt"
)
func main() {
ch := make(chan string, 2)
ch <- "naveen"
ch <- "paul"
fmt.Println(<- ch)
fmt.Println(<- ch)
}
在上面程式里的第 9 行,我們創建了一個緩沖信道,其容量為 2,由于該信道的容量為 2,因此可向它寫入兩個字串,而且不會發生阻塞,在第 10 行和第 11 行,我們向信道寫入兩個字串,該信道并沒有發生阻塞,我們又在第 12 行和第 13 行分別讀取了這兩個字串,
該程式輸出結果為
naveen
paul
下面緩沖信道的實體中有一個并發的 Go 協程來向信道寫入資料,而 Go 主協程負責讀取資料,這個例子解釋了向緩沖信道寫入資料時,什么時候會發生阻塞,
package main
import (
"fmt"
"time"
)
func write(ch chan int) {
for i := 0; i < 5; i++ {
ch <- i
fmt.Println("successfully wrote", i, "to ch")
}
close(ch)
}
func main() {
ch := make(chan int, 2)
go write(ch)
time.Sleep(2 * time.Second)
for v := range ch {
fmt.Println("read value", v,"from ch")
time.Sleep(2 * time.Second)
}
}
在上面的程式中,在Go 主協程中創建了容量為 2 的緩沖信道 ch,而第 17 行把 ch 傳遞給了 write 協程,接下來 Go 主協程休眠了兩秒,在這期間,write 協程在并發地運行,write 協程有一個 for 回圈,依次向信道 ch 寫入 0~4,而緩沖信道的容量為 2,因此 write 協程里立即會向 ch 寫入 0 和 1,接下來發生阻塞,直到 ch 內的值被讀取,因此,該程式立即列印出下面兩行:
successfully wrote 0 to ch
successfully wrote 1 to ch
列印上面兩行之后,write 協程中向 ch 的寫入發生了阻塞,直到 ch 有值被讀取到,而 Go 主協程休眠了兩秒后,才開始讀取該信道,因此在休眠期間程式不會列印任何結果,主協程結束休眠后,在第 19 行使用 for range 回圈,開始讀取信道 ch,列印出了讀取到的值后又休眠兩秒,這個回圈一直到 ch 關閉才結束,所以該程式在兩秒后會列印下面兩行:
successfully wrote 0 to ch
successfully wrote 1 to ch
- 該程序會一直進行,直到信道讀取完所有的值,并在 write 協程中關閉信道,最終輸出如下:
successfully wrote 0 to ch
successfully wrote 1 to ch
read value 0 from ch
successfully wrote 2 to ch
read value 1 from ch
successfully wrote 3 to ch
read value 2 from ch
successfully wrote 4 to ch
read value 3 from ch
read value 4 from ch
長度與容量
-
緩沖信道的容量是指信道可以存盤的值的數量,我們在使用 make 函式創建緩沖信道的時候會指定容量大小,
-
緩沖信道的長度是指信道中當前排隊的元素個數,
package main
import (
"fmt"
)
func main() {
ch := make(chan string, 3)
ch <- "naveen"
ch <- "paul"
fmt.Println("capacity is", cap(ch))
fmt.Println("length is", len(ch))
fmt.Println("read value", <-ch)
fmt.Println("new length is", len(ch))
}
在這個程式中,我們創建了一個容量為 3 的信道,于是它可以保存 3 個字串,
接下來分別在第 9 行和第 10行向信道寫入了兩個字串,于是信道有兩個字串排隊,因此其長度為 2,
在第13行,又從信道讀取了一個字串,現在該信道內只有一個字串,因此其長度變為 1,
該程式會輸出:
capacity is 3
length is 2
read value naveen
new length is 1
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/282680.html
標籤:區塊鏈
上一篇:golang完成聊天室功能
