1. 程式人生 > 實用技巧 >go routine + channel 實踐

go routine + channel 實踐

做個實驗,造一個長度一個億的slice struct

對其內部作出修改,分別使用併發和不用併發,看看時間上會差多少。

不使用協程版本:

type Data struct {
Id int
Info string
}
func main(){
//channel := make(chan[]Data,10)
var data []Data
for i:= 0;i<1e8;i++{
data = append(data,Data{Id: i,Info: "a"})
}
startTime := time.Now().UnixNano()


for i := 0;i<len(data);i++{
data[i].Info+="b"
}
//var wg sync.WaitGroup
//for i := 0;i<10;i++{
// wg.Add(1)
// go process(data[i*1e7:(i+1)*1e7],channel,&wg)
//}
//wg.Wait()
//data = data[:0]
//for i := 0;i <10;i++ {
// var tmp []Data
// tmp = <-channel
// data = append(data, tmp...)
//}
//close(channel)


endTime:= time.Now().UnixNano()
tag:=0
for _,v:= range data{
if v.Info!="ab"{tag++}
}
fmt.Printf("tag: %d\nlength: %d\n",tag,len(data))
fmt.Printf("running time: %d ms",(endTime-startTime)/1e6)
}
func process(ar []Data,channel chan []Data,wg *sync.WaitGroup){
defer wg.Done()
for i := 0;i<len(ar);i++{
ar[i].Info+="b"
}
channel <- ar
}

輸出:

tag: 0
length: 100000000
running time: 3080 ms

解釋:tag用來驗證是否所有Data都被修改,length用來驗證最後有沒有拿到完整的一個億的slice struct

tag =0 length=1e8說明咱程式碼結果是正確的。

使用協程版本:

package main

import (
"fmt"
"sync"
"time"
)

type Data struct {
Id int
Info string
}
func main(){
channel := make(chan[]Data,10)
var data []Data
for i:= 0;i<1e8;i++{
data = append(data,Data{Id: i,Info: "a"})
}
startTime := time.Now().UnixNano()


//for i := 0;i<len(data);i++{
// data[i].Info+="b"
//}
var wg sync.WaitGroup
for i := 0;i<10;i++{
wg.Add(1)
go process(data[i*1e7:(i+1)*1e7],channel,&wg)
}
wg.Wait()
data = data[:0]
for i := 0;i <10;i++ {
var tmp []Data
tmp = <-channel
data = append(data, tmp...)
}
close(channel)


endTime:= time.Now().UnixNano()
tag:=0
for _,v:= range data{
if v.Info!="ab"{tag++}
}
fmt.Printf("tag: %d\nlength: %d\n",tag,len(data))
fmt.Printf("running time: %d ms",(endTime-startTime)/1e6)
}
func process(ar []Data,channel chan []Data,wg *sync.WaitGroup){
defer wg.Done()
for i := 0;i<len(ar);i++{
ar[i].Info+="b"
}
channel <- ar
}

輸出:

tag: 0
length: 100000000
running time: 896 ms

解釋:tag和length依然正確,不再贅述。

開了十個routinue,時間上大概快了三到四倍,看到米有,這就是go routinue+channel的效果~~~~~~~

菜菜的我再多說幾句番外~~~~~~~~~~~:

1.如果沒有給channel緩衝區的話,就會死鎖,原因嘛,老八股文了,無緩衝區的channel寫入以後不消費掉的話寫入是阻塞的。所以加個緩衝區就好了。

2.如果不使用sync 的withGroup,就會奇妙的發現tag不等於0,也就意味著有一堆Data沒有修改成功,原因嘛,老八股文了,routine沒有執行完嘛。。。。

withGroup add done wait配合操作,讓他執行完再消費就好了。