Skip to main content

多线程轮流打印问题

8 min read

实现两个协程,其中一个产生随机数并写入到 chan 中,另一个从 chan 中读取,并打印出来,最终输出 5 个随机数

经典的“生产者消费者问题”

固定值交替打印

tip

固定值交替打印比较简单

可以看到,无论是打印数字,还是打印字母,实际上没有区别。无非是打印数字可以直接通过遍历 make(chan token)

核心是构造一个current channext chan的方法

常见题目如下:

  • 假设有 4 个协程,分别编号为 1/2/3/4,每秒钟会有一个协程打印出自己的编号,现在要求输出编号总是按照 1/2/3/4 这样的顺序打印,共打印 100 次
  • 编写一个程序,开启 3 个线程,这 3 个线程的 ID 分别为 A、B、C,每个线程将自己的 ID 在屏幕上打印 10 遍,要求输出结果必须按 ABC 的顺序显示;如:ABCABC...依次递推
  • 轮流打印 dog pig cat,共打印 10 次?
  • 两个人 bob 和 annie,互相喊对方的名字 10 次后,最终 bob 对 annie 说 bye bye?

无非是打印点什么数字、字符串之类的东西。我们这里就以打印数字为例。


// 假设有 4 个协程,分别编号为 1/2/3/4; 每秒钟会有一个协程打印出自己的编号; 现在要求输出编号总是按照 1/2/3/4 这样的顺序打印; 共打印 100 次;
func main() {
inChan := make(chan int)
outChan := make(chan int)

go func() {
for i :=0; i< 100; i++ {
vx := []int{1, 2, 3, 4}
for _, v := range vx{
inChan <- v
}

// for i := 0; i < num; i++ {
// inChan <- num
// }
}
close(inChan)
}()

go func(inChan <-chan int){
for v := range inChan {
outChan <- v
time.Sleep(time.Second)
}

// for {
// token := <- inChan
// time.Sleep(time.Second)
// outChan <- token
// }

close(outChan)
}(inChan)

for out := range outChan {
fmt.Println(out)
}
}


多线程数字 + 字母

tip

*这类问题比固定值要稍微复杂一些,但是与线程本身无关,这类题目往往有一些小技巧需要注意。

  • 使用两个协程交替打印序列,一个协程打印数字,另一个协程打印字母,最终效果如下1A2B...26Z
  • 用三个线程,顺序打印字母 A-Z,输出结果是 1A 2B 3C 1D 2E...打印完毕最后输出一个 OK
  • 实现两个协程,其中一个产生随机数并写入到 chan 中,另一个从 chan 中读取,并打印出来,最终输出 5 个随机数
  • 给一个数组,并发交替打印奇数和偶数,请分别用 chan、sync 和原子操作实现?

package main

import (
"fmt"
"sync"
)

func main() {
numberCh := make(chan int)
letterCh := make(chan rune)

var wg sync.WaitGroup
wg.Add(2)

go func() {
defer wg.Done()
for i := 1; i <= 26; i++ {
fmt.Print(<-numberCh)
fmt.Print(string(<-letterCh))
}
}()

go func() {
defer wg.Done()
for i := 'A'; i <= 'Z'; i++ {
numberCh <- int(i - 'A' + 1)
letterCh <- i
}
}()

wg.Wait()
close(numberCh)
close(letterCh)

fmt.Println()
}

多线程纯数字打印

tip

这里只列举一下第一题的几种解法,其他几个变种题目可以自己实现一下

实际上也是某种“非固定值打印”

这种问题嘛,就是多此一举,实际上就是循环一个 go func,该 func 里再起个循环打印就可以了。

  • 10 个线程依次打印 1-10,11-20 和到 100?
  • 三个线程交替打印至 100:线程 1 打印 1、4、7,线程 2 打印 2、5、8,线程 3 打印 3、6、9,一直打印到 100 结束
  • 如何让 10 个线程按照顺序打印 0123456789?
  • 怎么开 10 个线程,每个线程打印 1000 个数字,要按照顺序从 1 打印到 1w?
  • 用五个线程,顺序打印数字 1~无穷大,其中每 5 个数字为 1 组,如下:其中 id 代表线程的 id

这几个都可以分别用 chan、mutex、wg 和 atomic 实现一下,非常简单


Go Playground - The Go Programming Language