go語(yǔ)言實(shí)現(xiàn)并發(fā)
通過(guò)go 實(shí)現(xiàn)并發(fā)操作
func say(s string) {
for i := 0; i < 5; i++ {
fmt.Println(s)
}
}
func main(){
go say("hello")
say("world")
}
執(zhí)行上述代碼让腹,會(huì)間隔執(zhí)行say方法
通過(guò)channel實(shí)現(xiàn)并發(fā)數(shù)據(jù)間的通信
channel的創(chuàng)建必須通過(guò)make方式實(shí)現(xiàn)
ch := make(chan int)
channel通過(guò)操作符<-接收和發(fā)送數(shù)據(jù)
ch <- value //發(fā)送value到channel ch
value := <-ch //從channel ch中獲取數(shù)據(jù)
下面開(kāi)始是此節(jié)的重點(diǎn)內(nèi)容朝聋,廢話不多說(shuō)先上代碼
代碼1:
func sum(a []int, c chan int) {
fmt.Println("開(kāi)始往channel中寫數(shù)據(jù)", a)
total := 0
for _, v := range a {
total += v
}
c <- total
fmt.Println("單次寫數(shù)據(jù)處理完成")
}
func main() {
a := []int{1, 2, 3, 4}
c := make(chan int)
fmt.Println("write")
sum(a[:len(a)/2], c)
sum(a[len(a)/2:], c)
fmt.Println("write end")
}
控制臺(tái)輸出:
write
開(kāi)始往channel中寫數(shù)據(jù) [1 2]
單次寫數(shù)據(jù)處理完成
開(kāi)始往channel中寫數(shù)據(jù) [3 4]
fatal error: all goroutines are asleep - deadlock!
程序出現(xiàn)錯(cuò)誤见间,因?yàn)槲覀儎?chuàng)建一個(gè)未指定緩沖大小的channel(當(dāng)未指定緩沖大小時(shí)结序,channel默認(rèn)為0),
我們調(diào)用兩次channel的寫操作预烙,出現(xiàn)了阻塞
代碼2:
func sum(a []int, c chan int) {
fmt.Println("開(kāi)始往channel中寫數(shù)據(jù)", a)
total := 0
for _, v := range a {
total += v
}
fmt.Println("單次寫數(shù)據(jù)處理完成")
c <- total
}
func main() {
a := []int{1, 2, 3, 4}
c := make(chan int, 2)//這里我們指定channel的緩沖為2
fmt.Println("write")
sum(a[:len(a)/2], c)
sum(a[len(a)/2:], c)
fmt.Println("write end")
}
控制臺(tái)輸出:
write
開(kāi)始往channel中寫數(shù)據(jù) [1 2]
單次寫數(shù)據(jù)處理完成
開(kāi)始往channel中寫數(shù)據(jù) [3 4]
單次寫數(shù)據(jù)處理完成
write end
程序正常結(jié)束正塌,因?yàn)槲覀冎付薱hannel的緩沖大小,所以可以進(jìn)行兩次寫操作
代碼3:
func sum(a []int, c chan int) {
fmt.Println("開(kāi)始往channel中寫數(shù)據(jù)", a)
total := 0
for _, v := range a {
total += v
}
fmt.Println("單次寫數(shù)據(jù)處理完成")
c <- total
}
func main() {
a := []int{1, 2, 3, 4}
c := make(chan int)//如果我們不指定channel的緩沖大小如何實(shí)現(xiàn)兩次寫操作呢
fmt.Println("write")
go sum(a[:len(a)/2], c)
go sum(a[len(a)/2:], c)
fmt.Println("write end")
}
控制臺(tái)輸出:
write
write end
程序正常結(jié)束呛每,這是因?yàn)槲覀兪褂貌l(fā)調(diào)用調(diào)用sum方法
代碼4:
var (
wg sync.WaitGroup
)
func sum(a []int, c chan int) {
fmt.Println("開(kāi)始往channel中寫數(shù)據(jù)", a)
total := 0
for _, v := range a {
total += v
}
fmt.Println("單次寫數(shù)據(jù)處理完成")
c <- total
wg.Done()
}
func main() {
wg.Add(2)
a := []int{1, 2, 3, 4}
c := make(chan int)
fmt.Println("write")
go sum(a[:len(a)/2], c)
go sum(a[len(a)/2:], c)
fmt.Println("write end")
wg.Wait()
}
控制臺(tái)輸出:
fatal error: all goroutines are asleep - deadlock!
write
write end
程序異常踩窖,我們?cè)谥骶€程采用WaitGroup保持主線程不被銷毀,這樣異步線程就有時(shí)間進(jìn)行處理晨横,造成chan阻塞洋腮,代碼4未發(fā)生阻塞,是因?yàn)橹骶€程立刻就結(jié)束
代碼5:
func sum(a []int, c chan int) {
fmt.Println("開(kāi)始往channel中寫數(shù)據(jù)", a)
total := 0
for _, v := range a {
total += v
}
fmt.Println("單次寫數(shù)據(jù)處理完成")
c <- total
}
func main() {
a := []int{1, 2, 3, 4}
c := make(chan int,1)//我們指定channel的緩沖大小為1手形,但是我們調(diào)用兩次寫操作啥供,其中一次為并發(fā)調(diào)用
fmt.Println("write")
go sum(a[:len(a)/2], c)
sum(a[len(a)/2:], c)
fmt.Println("write end")
fmt.Println("read x")
x := <-c
fmt.Println("x = ", x)
fmt.Println("read Y")
y := <-c
fmt.Println("y = ", y)
fmt.Println("read end")
}
控制臺(tái)輸出:
write
開(kāi)始往channel中寫數(shù)據(jù) [3 4]
單次寫數(shù)據(jù)處理完成
write end
read x
x = 7
read Y
開(kāi)始往channel中寫數(shù)據(jù) [1 2]
單次寫數(shù)據(jù)處理完成
y = 3
read end
程序正常結(jié)束,可以看到首先執(zhí)行了main線程調(diào)用的sum方法库糠,
然后進(jìn)行一次x值的讀取伙狐,取得的為main線程寫入的數(shù)據(jù),
再進(jìn)行一次y值的讀取瞬欧,先進(jìn)行了數(shù)據(jù)的寫入贷屎,然后返回寫入的值
代碼6:
func sum(a []int, c chan int) {
fmt.Println("開(kāi)始往channel中寫數(shù)據(jù)", a)
total := 0
for _, v := range a {
total += v
}
fmt.Println("單次寫數(shù)據(jù)處理完成")
c <- total
}
func main() {
a := []int{1, 2, 3, 4}
c := make(chan int,2)//我們指定channel的緩沖大小為2
fmt.Println("write")
sum(a[:len(a)/2], c)
sum(a[len(a)/2:], c)
fmt.Println("write end")
fmt.Println("read x")
x := <-c
fmt.Println("x = ", x)
fmt.Println("read Y")
y := <-c
fmt.Println("y = ", y)
fmt.Println("read end")
}
控制臺(tái)輸出:
write
開(kāi)始往channel中寫數(shù)據(jù) [1 2]
單次寫數(shù)據(jù)處理完成
開(kāi)始往channel中寫數(shù)據(jù) [3 4]
單次寫數(shù)據(jù)處理完成
write end
read x
x = 3
read Y
y = 7
read end
程序正常結(jié)束,可以看到首先執(zhí)行兩次main線程調(diào)用的sum方法艘虎,然后分別x,y獲取兩次寫入的值
代碼7:
func sum(a []int, c chan int) {
fmt.Println("開(kāi)始往channel中寫數(shù)據(jù)", a)
total := 0
for _, v := range a {
total += v
}
fmt.Println("單次寫數(shù)據(jù)處理完成")
c <- total
}
func main() {
a := []int{1, 2, 3, 4}
c := make(chan int)//我們未指定channel的緩沖大小
fmt.Println("write")
go sum(a[:len(a)/2], c)
go sum(a[len(a)/2:], c)
fmt.Println("write end")
fmt.Println("read x")
x := <-c
fmt.Println("x = ", x)
fmt.Println("read Y")
y := <-c
fmt.Println("y = ", y)
fmt.Println("read end")
}
控制臺(tái)輸出:
write
write end
read x
開(kāi)始往channel中寫數(shù)據(jù) [3 4]
單次寫數(shù)據(jù)處理完成
x = 7
read Y
開(kāi)始往channel中寫數(shù)據(jù) [1 2]
單次寫數(shù)據(jù)處理完成
y = 3
read end
程序正常結(jié)束唉侄,可以看到我們異步調(diào)用兩次sum方法,
然后main線程獲取x值野建,輸入第二次異步的日志属划,同時(shí)返回寫入的數(shù)據(jù),
獲取y值贬墩,輸入第一次異步的日志榴嗅,同時(shí)返回寫入的數(shù)據(jù)
通過(guò)range獲取channel數(shù)據(jù)
range獲取channel的數(shù)據(jù)跟普通的<-唯一的區(qū)別在于需要顯形的關(guān)閉channel
close(ch)
廢話不多說(shuō)繼續(xù)上代碼
代碼1:
func fibonacci(n int, c chan int) {
x, y := 1, 1
fmt.Println("開(kāi)始往channel中寫數(shù)據(jù)", n)
for i := 0; i < n; i++ {
c <- x
x, y = y, x+y
}
fmt.Println("單次寫數(shù)據(jù)處理完成")
}
func main() {
ch2 := make(chan int)
fmt.Println("開(kāi)始range的寫操作")
go fibonacci(10, ch2)
fmt.Println("寫操作結(jié)束")
fmt.Println("開(kāi)始range的讀操作")
for i := range ch2 {
fmt.Println(i)
}
fmt.Println("讀操作結(jié)束")
}
控制臺(tái)輸出:
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.main()
/Users/cheyongzi/Desktop/data/project/GoDemo/routine/runtime.go:66 +0x242
開(kāi)始range的寫操作
寫操作結(jié)束
開(kāi)始range的讀操作
開(kāi)始接收
1
1
2
3
5
8
13
21
34
55
程序異常退出,這是因?yàn)閞ange獲取channel的數(shù)據(jù)需要顯性的調(diào)用close方法關(guān)閉channel
代碼1:
func fibonacci(n int, c chan int) {
x, y := 1, 1
fmt.Println("開(kāi)始往channel中寫數(shù)據(jù)", n)
for i := 0; i < n; i++ {
c <- x
x, y = y, x+y
}
close(c)
fmt.Println("單次寫數(shù)據(jù)處理完成")
}
func main() {
ch2 := make(chan int)
fmt.Println("開(kāi)始range的寫操作")
go fibonacci(10, ch2)//這里如果不采用異步調(diào)用陶舞,則需要在ch2定義的時(shí)候指定緩沖大小嗽测,否則會(huì)報(bào)錯(cuò)
fmt.Println("寫操作結(jié)束")
fmt.Println("開(kāi)始range的讀操作")
for i := range ch2 {
fmt.Println(i)
}
fmt.Println("讀操作結(jié)束")
}
控制臺(tái)輸出:
開(kāi)始range的寫操作
寫操作結(jié)束
開(kāi)始range的讀操作
開(kāi)始接收
1
1
2
3
5
8
13
21
34
55
讀操作結(jié)束
程序正常運(yùn)行