依次打印
题目:依次输出 dog、pig、sheep,并执行 100 次,每个输出都需要一个单独的 goroutine
这里我们通过有缓冲的容量为 1 的 channel 来标记状态,通过 for-select 结构来控制当前要输出哪一个单词,因为 select 在 channel 阻塞的时候不会执行对应的 case,我们可以通过这个特性来操作。
具体思路如下:
- 设置三个 channel,初始化时使 dog 的 channel 中有一条数据,这样 select 就会先输出 dog
- 然后在 dog 的 case 中结束的时候给 pig 的 channel 中新增一条数据,这样下次就会进入 pig 的 case 进行输出操作
- 过程中我们可以使用 atomic 包来控制次数,不会产生并发问题
具体代码如下:
package main
import
(
"fmt"
"sync"
"sync/atomic"
)
var wg sync.WaitGroup
var counter uint64 = 0
var dogChan = make(chan struct{}, 1)
var pigChan = make(chan struct{}, 1)
var sheepChan = make(chan struct{}, 1)
func main() {
wg.Add(1)
go animalPrint()
dogChan <- struct{}{}
wg.Wait()
}
func animalPrint() {
for {
if counter == uint64(300) {
wg.Done()
return
}
select {
case <-dogChan:
fmt.Println("dog")
atomic.AddUint64(&counter, 1)
pigChan <- struct{}{}
case <-pigChan:
fmt.Println("pig")
atomic.AddUint64(&counter, 1)
sheepChan <- struct{}{}
case <-sheepChan:
fmt.Println("sheep")
atomic.AddUint64(&counter, 1)
dogChan <- struct{}{}
}
}
}
是不是觉得重复代码有点多? 我们还是依照上面的思路,把代码换种方式实现:
package main
import
(
"fmt"
"sync"
"sync/atomic"
)
var wg sync.WaitGroup
var counter uint64 = 0
var dogChan = make(chan struct{}, 1)
var pigChan = make(chan struct{}, 1)
var sheepChan = make(chan struct{}, 1)
func main() {
wg.Add(3)
dogChan <- struct{}{}
go animalPrint2("dog", dogChan, pigChan)
go animalPrint2("pig", pigChan, sheepChan)
go animalPrint2("sheep", sheepChan, dogChan)
wg.Wait()
}
func animalPrint2(name string, curChan, nextChan chan struct{}) {
cnt := 0
for {
if cnt == 100 {
wg.Done()
break
}
<-curChan
cnt++
println(name)
nextChan <- struct{}{}
}
}
交替打印
我们把问题扩展一下,如果打印的顺序是交替打印呢?还可以用这样的思路实现么?
问题:交替打印数字和字母,实现如下效果: 12AB34CD56EF78GH910IJ1112KL1314MN1516OP1718QR1920ST2122UV2324WX2526YZ
思路一样,代码如下:
package main
import
(
"fmt"
"sync"
)
var wg sync.WaitGroup
var numChan = make(chan struct{}, 1)
var byteChan = make(chan struct{}, 1)
func main() {
wg.Add(2)
numChan <- struct{}{}
go numPrint()
go bytePrint()
wg.Wait()
}
func numPrint() {
i := 1
for {
if i == 27 {
wg.Done()
break
}
<-numChan
println(i, i+1)
i += 2
byteChan <- struct{}{}
}
}
func bytePrint() {
i := 'A'
for {
if i > 'Z' {
wg.Done()
break
}
<-byteChan
fmt.Printf("%c%c", i, i+1)
i += 2
numChan <- struct{}{}
}
}
如果你有其他更好的思路,希望你告诉我,这个确实有意思