非缓冲通道的工作方式是读协程在读取chan时,若读取不到会就会阻塞在那里,直到读取到数据为止。写入也是这样如果没有其它协程读取本次的写入,写入协程也同样会阻塞在这里等待。
这种方式明显降低程序运行的效率,如果能写与读互不阻塞是不是就会快很多呢? 可不可以相互约定一块空间,我把数据放在指定的地方,读取者也去指定的地方读取,这样我把数据放在那里后立刻就可以去做别的事情。
缓冲chan就可以做这件事情,上缓冲chan代码:
package main
import (
"fmt"
"time"
)
func worker1(in chan<- string) {
fmt.Printf("%d\n",1)
in <- "我"
time.Sleep(time.Millisecond*500)
fmt.Printf("%d\n",2)
in <- "是"
time.Sleep(time.Millisecond*500)
fmt.Printf("%d\n",3)
in <- "c"
time.Sleep(time.Millisecond*500)
fmt.Printf("%d\n",4)
in <- "h"
time.Sleep(time.Millisecond*500)
fmt.Printf("%d\n",5)
in <- "a"
time.Sleep(time.Millisecond*500)
fmt.Printf("%d\n",6)
in <- "n"
time.Sleep(time.Millisecond*500)
fmt.Printf("%d\n",7)
time.Sleep(time.Second*5)
}
func worker2(out <-chan string) {
value := ""
i:=0
for {
value = <-out
i++
fmt.Printf("out %d -> %s\n",i,value)
time.Sleep(time.Second*2)
}
}
func main() {
//创建缓冲chan
ch := make(chan string,3)
go worker1(ch)
go worker2(ch)
time.Sleep(10*time.Second)
}
运行结果:
1
out 1 -> 我
2
3
4
out 2 -> 是
5
6
out 3 -> c
7
out 4 -> h
out 5 -> a
分析:
创建缓冲大小为3的chan,预计缓冲区放满3个数据写入协程才会被阻塞。
为了让多协程代码尽量按照预计的路线运行,在代码关键地方加了time.Sleep,由于时间差的原因最多才会存满3个,是很有可能还没存满3个就被读取了。所以结果才会如上面那样
为了对比运行逻辑,再上一份非缓冲chan的程序,上代码:
package main
import (
"fmt"
"time"
)
func worker1(in chan<- string) {
fmt.Printf("%d\n",1)
in <- "我"
time.Sleep(time.Millisecond*500)
fmt.Printf("%d\n",2)
in <- "是"
time.Sleep(time.Millisecond*500)
fmt.Printf("%d\n",3)
in <- "c"
time.Sleep(time.Millisecond*500)
fmt.Printf("%d\n",4)
in <- "h"
time.Sleep(time.Millisecond*500)
fmt.Printf("%d\n",5)
in <- "a"
time.Sleep(time.Millisecond*500)
fmt.Printf("%d\n",6)
in <- "n"
time.Sleep(time.Millisecond*500)
fmt.Printf("%d\n",7)
time.Sleep(time.Second*5)
}
func worker2(out <-chan string) {
value := ""
i:=0
for {
value = <-out
i++
fmt.Printf("out %d -> %s\n",i,value)
time.Sleep(time.Second*2)
}
}
func main() {
ch := make(chan string,3)
go worker1(ch)
go worker2(ch)
time.Sleep(10*time.Second)
}
运行结果:
1
out 1 -> 我
2
out 2 -> 是
3
out 3 -> c
4
out 4 -> h
5
out 5 -> a
6
分析:
很明显的可以看出,非缓冲chan是相互阻塞交替运行的。
另外还有一个细节是信息没有输出完,这是因为协程睡眠十秒后就退出来,在它退出的时候会强制退出其它协程。