Golang面试题: 两个goroutine交替打印1

编程入门 行业动态 更新时间:2024-10-11 09:20:05

Golang<a href=https://www.elefans.com/category/jswz/34/1769418.html style=面试题: 两个goroutine交替打印1"/>

Golang面试题: 两个goroutine交替打印1

文章目录

  • 题目介绍
  • 做法一
  • 做法二
  • 做法三

开心一刻

       一个国王要替公主征婚,把一个苹果放在公主头上,谁要把它射中就有机会迎娶公主。

       第一个男士把苹果射中,他说:“I’m 罗宾。”

       第二个男士也把苹果射中,他说:“I’m 后羿。”

       第三个男士不小心把公主射死了,他说:“ I’m sorry…"

题目介绍

       使用两个goroutine交替打印1-100之间的奇数和偶数, 输出时按照从小到大输出.

做法一

package mainimport ("fmt""sync"
)func main() {ch := make(chan struct{})var wg sync.WaitGroupwg.Add(2)go func() {defer wg.Done()for i := 1; i < 101; i++ {ch <- struct{}{}//奇数if i%2 == 1 {fmt.Println("线程1打印:",i)}}}()go func() {defer wg.Done()for i := 1; i < 101; i++ {<- ch//偶数if i%2 == 0 {fmt.Println("线程2打印:",i)}}}()wg.Wait()
}

对做法一的理解:
       首先因为变量ch是一个无缓冲的channel, 所以只有读写同时就绪时才不会阻塞。所以两个goroutine会同时进入各自的 if 语句(此时 i 是相同的),但是此时只能有一个 if 是成立的,不管哪个goroutine快,都会由于读channel或写channel导致阻塞,因此程序会交替打印1-100且有顺序。

做法二

package mainimport ("fmt""sync"
)
var ch = make(chan struct{})
var wg sync.WaitGroup
func go1() {defer wg.Done()for i := 1; i <= 10; i += 2 {fmt.Println(i)ch <- struct{}{}//不能与上一行交换位置<- ch}
}
func go2() {defer wg.Done()for i := 2; i <= 10; i += 2 {<- chfmt.Println(i)ch <- struct{}{}}
}
func main() {wg.Add(2)go go1()go go2()wg.Wait()
}

对做法二的理解:
       做法二中两个goroutine分别打印奇数和偶数,在两个goroutine中每次for循环时fmt都能得到执行,所以为了实现交替打印1-100,需要使用两对无缓冲的channel。13行和20行构成第一对同步channel,14和22行构成第二对同步channel,第一对同步channel完成读取数据之前,奇数就已经打印;第二对同步channel完成打印之前,偶数就会打印,所以最终输出就是交替打印1-100。

       做法二虽然可以完成交替打印的工作,但是我觉得不具有可扩展性,例如三个协程如何交替打印ABC。后来在网上搜索了一下,发现有比较好的做法,并且也比较容易理解,而且还能扩展到N个协程交替打印数字。

package mainimport ("fmt""sync"
)
var ch1, ch2 = make(chan struct{}), make(chan struct{})
var wg sync.WaitGroup
func go1() {defer wg.Done()for i := 1; i <= 10; i += 2 {<- ch1fmt.Println(i)ch2 <- struct{}{}}<- ch1
}
func go2() {defer wg.Done()for i := 2; i <= 10; i += 2 {<- ch2fmt.Println(i)ch1 <- struct{}{}}
}
func main() {wg.Add(2)go go1()go go2()ch1 <- struct{}{}wg.Wait()
}

       对于做法二的改进方法,能够做到两个协程交替打印奇偶数,而且还能保证顺序。但是要注意代码16行的“<- ch1”,如果不加的话会报错,因为不加16行的代码,go2最终会被阻塞,wg.Done()无法被执行。

做法三

package mainimport ("fmt""runtime""sync"
)func main() {//设置可同时使用的CPU核数为1var wg sync.WaitGroupruntime.GOMAXPROCS(1)wg.Add(2)go func() {defer wg.Done()for i := 1; i < 101; i++ {//奇数if i%2 == 1 {fmt.Println("线程1打印:",i)}//让出cpuruntime.Gosched()}}()go func() {defer wg.Done()for i := 1; i < 101; i++ {//偶数if i%2 == 0 {fmt.Println("线程2打印:",i)}//让出cpuruntime.Gosched()}}()wg.Wait()
}

       runtime.Gosched这个函数的作用是让当前goroutine让出CPU,好让其它的goroutine获得执行的机会。同时,当前的goroutine也会在未来的某个时间点继续运行。

文中都是我个人的理解,如有错误的地方欢迎下方评论告诉我,我及时更正,大家共同进步

更多推荐

Golang面试题: 两个goroutine交替打印1

本文发布于:2024-02-10 22:35:37,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1677699.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:面试题   两个   Golang   goroutine

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!