go实现n个goroutine交替打印 1- 100
这道题是面试时经常遇到的一道题,是考察对goroutine和channel的应用
思路:创建等同goroutine数量的chan切片,每个chan通过阻塞的性质控制goroutine的顺序
go
func alternatingNGoroutine() {
chanNum := 5 // chan数量代表着goroutine数量
chanQueue := make([]chan int, chanNum) // chan切片
exitChan := make(chan bool) // 退出信号
res := 0
for i := 0; i < chanNum; i++ {
// 初始化chan切片的每个chan,无缓冲的
chanQueue[i] = make(chan int)
// 这个我在下面详细解释,很重要,没有这个会死锁
if i == chanNum-1 {
go func(i int) {
chanQueue[i] <- 1
}(i)
}
}
// for循环创建goroutine
for i := 0; i < chanNum; i++ {
// prevChan 是等前一个协程结束才能输出下一个,为了控制输出顺序
// curChan 控制当前阻塞输出的协程
var prevChan, curChan chan int
if i == 0 {
// chan切片想象成一个环,第一个切片的前一个就是chan切片的末尾,和上面相呼应,就是要给最后一个chan先发送一条消息
prevChan = chanQueue[chanNum-1]
} else {
// 记录前一个协程状态
prevChan = chanQueue[i-1]
}
// 记录当前协程
curChan = chanQueue[i]
go func(i int, prevChan, curChan chan int) {
for {
// 如果大于100就退出
if res > 100 {
exitChan <- true
}
// 一直阻塞到上一个输出完,控制顺序
<-prevChan
fmt.Println("goroutine", i, ": ", res)
res++
// 当前协程输出完
curChan <- 1
}
}(i, prevChan, curChan)
}
<-exitChan
fmt.Println("done...")
}
go
if i == chanNum-1 {
go func(i int) {
chanQueue[i] <- 1
}(i)
}
1、这一步主要是给最后一个chan先发送数据,保证第一个chan可以取到数据不阻塞
2、必须要加协程去发送这条数据,不然直接死锁了,因为不是协程发数据就会一直阻塞导致死锁