今天看到一个有趣的问题,使用协程逐个打印出来“ABCABCABC”,简单尝试了一下,创建三个channel即可,按顺序往每一个channel中发送数据,再从下一个channel里面读取数据。再使用一个channel用于标记是否已经完成
func main() {
c1 := make(chan int32)
c2 := make(chan int32)
c3 := make(chan int32)
done := make(chan struct{})
// 协程A,打印A并向协程B发送信号
go func() {
count := 0
for {
<-c1
fmt.Print("A")
c2 <- 1
count++
if count >= 3 {
return
}
}
}()
// 协程B,打印B并向协程C发送信号
go func() {
count := 0
for {
<-c2
fmt.Print("B")
c3 <- 1
count++
if count >= 3 {
return
}
}
}()
// 协程C,打印C并向协程A发送信号
go func() {
count := 0
for {
<-c3
fmt.Print("C")
count++
if count >= 3 {
return
}
c1 <- 1
}
}()
// 启动第一个协程
c1 <- 1
// 等待程序结束
<-done
}
执行完的结果,确实是可以打印出来“ABCABCABC”,但是有一个小问题是,代码行数过多,同时,如果需要我们打印A-Z呢,这样写26遍go func(),估计能崩溃(倒是可以凑上百行代码,哈哈哈哈)
于是需要做一些优化了。
下面是一个很经典的错误写法!
func words() {
count := 0
chs := make([]chan bool, 26)
done := make(chan int)
for {
for i := range chs {
chs[i] = make(chan bool)
go func(i int) {
<-chs[i]
fmt.Printf("%c ", 'A'+i)
chs[(i+1)%26] <- true
if i == 25 {
count++
}
}(i)
}
if count == 3 {
<-chs[25]
done <- 1
break
}
}
chs[0] <- true
<-done
}
这个代码会直接进入死循环,卡住。
这里的主要问题是,协程的理解,还是按照python语言的思维方式,在外层用循环,导致不停地创建chan,但是对应的每一个协程都在等待读取,没有进展下去。
修改后的可用代码如下:
func words() {
chs := make([]chan bool, 26)
done := make(chan int)
for i := 0; i < 26; i++ {
chs[i] = make(chan bool)
go func(i int) {
count := 0
for {
<-chs[i]
fmt.Printf("%c ", 'A'+i%26)
//fmt.Printf("%d", i)
if i < 25 {
chs[(i+1)%26] <- true
}
count++
if count >= 3 {
if i == 25 {
done <- 1
}
return
}
if i == 25 {
chs[(i+1)%26] <- true
}
}
}(i)
}
chs[0] <- true
<-done
}
简单的理解一下就是,先创建好26个channel,然后给chs[0]写入一个值,让整个流程转起来,然后就等着done即可。