关于Channel这种GO语言并发原语
其实channel已经在另外一篇博客里面有曾经提到过,其使用起来是阻塞的(非buffered),所以比较容易造成dead lock。今天主要总结其两种比较优秀的应用场景:1.生产者和消费者的场景;2.用于替换WaitGroup的场景。
生产者和消费者的场景
具体代码见下:
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
c := make(chan int)
for i := 0; i < 4; i++ {
go producer(c)
}
for {
res := <- c
fmt.Println(res)
}
}
func producer(c chan int) {
for {
time.Sleep(time.Duration(rand.Intn(1000))* time.Millisecond)
c <- rand.Int()
}
}
简而言之,上述代码就是生成了4个随机数生产者,不停地向通道中生产输出随机数,因此也需要不停地从通道中去取数据,不然将会造成死锁。
WaitGroup场景
WaitGroup适用于一组线程协作一起完成某项任务后,一起退出或者继续向下执行的场景。见下:
package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go func(x int) {
sendRpc(x)
wg.Done()
}(i)
}
wg.Wait()
}
func sendRpc(x int) {
fmt.Println(x)
}
而上述过程也可以通过利用channel来完美替换实现,见下:
package main
import "fmt"
func main() {
done := make(chan bool)
for i := 0; i < 5; i++ {
go func(x int) {
sendRpc2(x)
done <- true
}(i)
}
for i := 0; i < 5; i++ {
<- done
}
}
func sendRpc2(x int) {
fmt.Println(x)
}
简要总结
channel的适用场景比较典型,但是一般还是不建议使用channel,除非你非常清楚他在干什么,尽量还是多使用mutex以及共享变量来解决多线程的问题。