【go】goroutine 交替打印又忘了?你该怎么不忘?
2023-12-25 23:01:40
说明:别再忘了,不会忘了,必须的
就是这题用来理解 goroutine 很不错,同时是大厂面试喜欢问的,毕竟这题不难,但重在你是否真的理解了,理解了就好记忆一点
但是记忆除了理解还有很多方法,今天就让你既理解,又记忆长久
题目:两个 goroutine 交替打印 1-100
或者字母数字什么啦,都一样,重在交替而已,别的只是一点点条件不同
接下来我会说两种,一种有缓冲,一种没缓冲,看懂一种,另一种都非常好理解和记忆了
1、有缓冲
现在呢,咱们别看代码,先想一下怎么写
- 首先呢,肯定要声明两个 chan,例如chanOne,chanTwo,用make 这很简单不说了
- 接着呢,要打印,因为是有缓冲的,假设咱们设置的缓冲大小是 1(这可能有别的问题,死锁,刚开始不用想这么多),
- chanOne 先放进去一个随便
开始第一个 go func,协程
- 接着开始写go func,协程,写一个 for 循环,i从1开始,每次自增2,我们从 chanOne 取出来,如果可以取出来,那就是可以执行下一步啦,就是打印 i,接着往 chanTwo 随便塞入一个数
- 诶嘿,当第二次执行for发现 chanOne 空了,取不出来了,就被阻塞
- 知识点哈,chan为空,取的时候会阻塞
开始第二个 go func ,协程
- 是的,步骤和上边一样哈哈,此时,chanTwo 不为空,就可以执行 fmt.Print啦,往 chanOne 发一个随便的数字,诶嘿,此时chanOne的for又可以执行啦,从此循环即可啦
问题
- 这样结束,不知道你发现没有,最后是不会打印的
- 果然想象很美好,现实很骨感啊~~(别想你的小姐姐啦)
- 仔细回顾一下,问题出在了这里,goroutine的执行顺序是不确定的,并不是我把chanOne写在了前边就执行前边的
- 知识点:chan为空,读的时候也会阻塞
- 所以如果先执行了第二个goroutine,就 chanTwo 本来就为空,就直接阻塞了,也就不会不会全部打印完,死锁了,一个在等待接受一个在等待发送,这就是设置缓冲大小为 1,同时又不做同步的问题,死锁,但其实就算你不设置为 1 ,设置 10 ,还是一样的道理的,还是设置 1 好点
解决办法
实现同步,同步的方式
- time.Sleep(1 * time.Second) 一行解决,但不推荐
- 用 WaitGroup ,推荐
- 其实也可以用 Mutex ,但没必要,加锁性能就不好了
func main() {
supersedeChannel()
}
func supersedeChannel() {
// 两个 goroutine 交替打印法,两个chan
chanOne := make(chan int, 1)
chanTwo := make(chan int, 1)
wg := sync.WaitGroup{}
wg.Add(2)
chanOne <- 1
go func() {
defer wg.Done()
for i := 1; i <= 100; i += 2 {
<-chanOne
fmt.Printf("%v,", i)
chanTwo <- i
}
}()
go func() {
defer wg.Done()
for i := 2; i <= 100; i += 2 {
<-chanTwo
fmt.Printf("%v,", i)
chanOne <- i
}
}()
fmt.Println("嗯嗯嗯嗯嗯嗯嗯嗯呢")
//time.Sleep(1 * time.Second) // 为什么加了这一行就能打印出来,不加这一行就打印不出来
wg.Wait()
fmt.Println("哈哈哈哈哈哈哈哈")
}
2、无缓冲
有缓冲懂了,这个无缓冲,那还不手到擒来
func main() {
supersedeChannel()
}
func supersedeChannel() {
// 两个 goroutine 交替打印法,使用 channel 同步
chanOne := make(chan bool)
chanTwo := make(chan bool)
done := make(chan bool)
go func() {
defer close(done)
for i := 1; i <= 100; i += 2 {
<-chanOne
fmt.Printf("%v,", i)
chanTwo <- true
}
}()
go func() {
//defer close(chanOne)
defer close(chanTwo)
for i := 2; i <= 100; i += 2 {
<-chanTwo
fmt.Printf("%v,", i)
chanOne <- true
}
}()
fmt.Println("enennenenennenenene")
chanOne <- true // 启动交替打印的循环
<-done
fmt.Println("\n哈哈哈哈哈哈哈哈")
}
文章来源:https://blog.csdn.net/EGXXM/article/details/135209141
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!