Go的不定期笔记 [1]——理解生产消费

[0offer转Go的过程]

看到部分面经有手写交替打印的题目,这里以交替打印cat,dog,fish各100次为例子
包含一个错误解法和一个正确解法:
错误解法

package main

import "fmt"

func main() {
	fmt.Println("正在打印")

	ch1 := make(chan bool)
	ch2 := make(chan bool)
	ch3 := make(chan bool)
	exit := make(chan bool)

	go func() {
		for i := 0; i < 100; i++ {
			if ok := <-ch1; ok {
				fmt.Printf("cat %d\n", i)
				ch2 <- true
			}
		}
	}()
	go func() {
		for i := 0; i < 100; i++ {
			if ok := <-ch2; ok {
				fmt.Printf("dog %d\n", i)
				ch3 <- true
			}
		}
	}()
	go func() {
		defer func() { exit <- true }()
		for i := 0; i < 100; i++ {
			if ok := <-ch3; ok {
				fmt.Printf("fish %d\n", i)
			}
		}
	}()

	ch1 <- true
	<-exit
}

这里报错的原因对初学者还是蛮难察觉到的(有兴趣可以自己分析)
正确解法

package main

import "fmt"

func main() {
	fmt.Println("正在打印")

	ch1 := make(chan bool)
	ch2 := make(chan bool)
	ch3 := make(chan bool)
	exit := make(chan bool)

	go func() {
		for i := 0; i < 100; i++ {
			if ok := <-ch1; ok {
				fmt.Printf("cat %d\n", i)
				ch2 <- true
			}
		}
	}()
	go func() {
		for i := 0; i < 100; i++ {
			if ok := <-ch2; ok {
				fmt.Printf("dog %d\n", i)
				ch3 <- true
			}
		}
	}()
	go func() {
		defer func() { exit <- true }()
		for i := 0; i < 100; i++ {
			if ok := <-ch3; ok {
				fmt.Printf("fish %d\n", i)
				if i != 99 { // 如果i等于99了,就不要再向ch1通道写数据了,否则将导致ch1通道死锁
					ch1 <- true
				}
			}
		}
	}()

	ch1 <- true
	<-exit
}

补充两点

  • 对于第三个也就是最后打印fish的goroutine在遍历结束后,需要添加defer来告知程序切换到主goroutine
  • 对于错误解法,出现的问题是在最后一次循环中,若仍然把true写入ch1,会造成没有接收,陷入阻塞
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值