前几篇对并发编程基础元素goroutine、channel、sync包有所了解,接下来可利用这部分内容组成可使用的并发模式。
for select 循环模式
多路复用的并发模式,直到满足某条件退出for循环
// 模式1:
for{
select{
case <-done
return
default:
//执行具体的内容
}
}
// 模式2:
for _,val := range []int{
select {
case <-done:
return
case resCh <-val:
...
if .. {
done <- ??
}
}
}
- 模式1:一直执行default语句中的任务,直到执行done后被关闭停止
- 模式2:有限循环,resCh接收循环的值,可通过满足某条件将值传递给done,这样就可以退出当前循环,或者其他方式
select timeout模式
请求数据时,因网络不同响应时间也不同,为避免出现一直等待那些超时请求,我们需要设置一个超时时间,可使用select timeout模式
select {
case v := <-result
...
case <-time.After(5 * time.Second)
fmt.Println("网络访问超时了")
}
主要通过time.After函数设置一个超时时间,防止因异常导致select语句无限等待。如果存在Context,可优先使用context.WithTimeout函数
Pipeline模式
管道模式(流水线模式),类似一个流水线生产,经过多个工序作业完成最后的成品。
- 流水线由多道工序构成,每道工序通过channel将数据传递到下一个工序,即每道工序的入参都是上游工序的返回值,产生的值继续传递给下游工序
- 每道工序对应一个函数,函数中有协程和channal,函数处理数据,并把它放在channel中,最后返回channel给下一道工序使用
- 组织者将所有工序串联起来,形成完整的流水线
//
func main(){
first := build1()
second := build2(first)
third := build3(second)
}
//工序1
func build1(in <-chan string) <-chan string{
out := make(chan string)
go func(){
defer close(out)
for c:= range in{
out <- "组装(“+c+”)"
}
}()
return out
}
// 工序2
func build2(in <-chan string) out chan string{
...
}
// 工序3
func build3(in <-chan string) out chan string{
...
}
扇出和扇入模式
扇出:多个函数可以从同一个通道读取数据,直到通道关闭
扇入:一个函数可以从多个通道读取数据,直到通道关闭
func main(){
in := gen(1)
c1 := sq(in)
c2 := sq(in)
for n := range merge(c1,c2){
fmt.Println(n)
}
}
func sq(in <-chan string) chan string{
out := make(chan string)
go func(){
...
}
return out
}