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配合操作,让他执行完再消费就好了。



 

posted @ 2020-10-10 12:12  埃姆提斯  阅读(145)  评论(0)    收藏  举报