无缓冲通道:同步通道
//对无缓冲channel类型的发送与接收操作,一定要放在两个不同的Goroutine中进行,否则会导致deadlock。
//无缓冲通道,必须接收和发送都准备好了才能执行。否则会阻塞。
//所以无缓冲通道相当于是同步通道了。
var helloChan = make(chan struct{})
func Test33() {
fmt.Println("数一下羊吧~~~")
go SaySheep()
<-helloChan //这里会暂时阻塞直到SaySheep遍历执行输出10只羊后收到helloChan通道发送的值才会继续下一步
fmt.Println("you are bad bad")
}
func SaySheep() {
for i := 0; i < 10; i++ {
fmt.Println("🐏")
}
helloChan <- struct{}{} //空结构体不占用内存
}
输出结果:
有缓冲通道:控制协程、并发的数量
//利用有缓冲通道控制协程的数量,利用waitGroup控制协程的结束
var wg sync.WaitGroup
func Test35() {
//利用有缓冲通道控制协程数量为3
ch := make(chan struct{}, 3)
for i := 0; i < 20; i++ {
wg.Add(1)
//这里缓冲通道写满了3个数据后,就会阻塞,等待Weekend方法中发送通道里的数据,才能继续执行
ch <- struct{}{}
go Weekend(ch, i)
}
wg.Wait()
}
func Weekend(ch chan struct{}, i int) {
fmt.Println("周末拉", i)
fmt.Println(" goroutine count = ", runtime.NumGoroutine())
// time.Sleep(time.Duration(i) * time.Second)
<-ch
wg.Done()
}
输出结果:
无缓冲通道也可以控制并发的数量
//无缓冲通道控制协程数量
//思想:开启固定的goroutine池,然后设置无缓冲的通道作为接收任务的中介,固定的协程读取到通道中任务就执行任务。
var wg sync.WaitGroup
func Test36() {
var cowChan = make(chan string)
var go_num = 3 //指定协程的数量为3
for i := 0; i < go_num; i++ {
go CallCowBoy(cowChan)
}
for i := 0; i < 20; i++ {
SendTask(cowChan, i)
//也可以直接写在这里
// wg.Add(1)
// cowChan <- "🐂🤠" + strconv.Itoa(i)
}
wg.Wait()
}
func CallCowBoy(ch chan string) {
for v := range ch {
fmt.Printf("%s are very busy \n", v)
fmt.Println(" goroutine count = ", runtime.NumGoroutine())
wg.Done()
}
}
func SendTask(ch chan string, i int) {
wg.Add(1)
ch <- "🐂🤠" + strconv.Itoa(i)
}