多个协程交替打印

652 阅读1分钟

1. 多个groutine交替打印数字和字母

//1.交替打印数字字母
//12AB34CD56EF......2526YZ

package main

import (
   "fmt"
   "sync"
)

var numChan, strChan = make(chan struct{}), make(chan struct{})
var wg1 sync.WaitGroup

//打印数字
func printNum() {
   defer wg1.Done()
   for i := 1; i <= 26; i += 2 {
      <-numChan                  // 阻塞直到字母被打印后 numChan写入
      fmt.Printf("%v%v", i, i+1) /// 打印数字
      strChan <- struct{}{}      // strChan写入,打印字母的协程的strChan取出,才会打印字母
   }
   <-numChan //读走最后一个从协程2传入的,防止死锁
}

//打印字母
func printStr() {
   defer wg1.Done()
   for i := 65; i <= 90; i += 2 {
      <-strChan
      fmt.Printf("%v%v", string(rune(i)), string(rune(i+1)))
      numChan <- struct{}{}
   }
}

func main() {
   wg1.Add(2)
   go printNum()
   go printStr()
   numChan <- struct{}{}
   wg1.Wait()
}

2. 多个groutine交替打印奇数和偶数

//2.两个协程交替打印 1-100 数字的奇数和偶数

package main

import (
   "fmt"
   "sync"
)

var ch1, ch2 = make(chan struct{}), make(chan struct{})
var wg sync.WaitGroup

//打印奇数
func odd() {
   defer wg.Done()
   for i := 1; i < 100; i += 2 {
      <-ch1
      fmt.Println("goroutine1:",i)
      ch2 <- struct{}{}
   }
   <-ch1 //读走最后一个从协程2传入的,防止死锁
}

//打印偶数
func even() {
   defer wg.Done()
   for i := 2; i <= 100; i += 2 {
      <-ch2
      fmt.Println("goroutine2:",i)
      ch1 <- struct{}{}
   }
}

func main() {
   wg.Add(2)
   go odd()
   go even()
   ch1 <- struct{}{}
   wg.Wait()
}

3. N个groutine交替打印

  1. 启动N个协程,共用一个外部变量计数器,计数器范围是1到100
  2. 开启N个有缓冲chan,chans[i]塞入数据代表协程i可以进行打印了
  3. 协程i一直阻塞,直到chan[i]通道有数据可以拉,才打印
//3. N个协程交替打印1-100
package main

import "fmt"

func main() {
   goroutineNum := 5
   var chanSlice []chan int
   exitChan := make(chan int)

   for i := 0; i < goroutineNum; i++ { //创建N个channel
      chanSlice = append(chanSlice, make(chan int, 1))
   }

   num := 1
   j := 0
   for i := 0; i < goroutineNum; i ++ { //创建N个协程
      go func(i int) {
         for {
            <-chanSlice[i] //循环阻塞等待
            if num > 100 {
               exitChan <- 1
               break
            }

            fmt.Println(fmt.Sprintf("gorutine%v:%v", i, num))
            num++

            if j == goroutineNum-1 { //j来控制启动哪个协程来打印
               j = 0
            }else {
               j ++
            }
            chanSlice[j] <- 1
         }
      }(i)
   }
   chanSlice[0] <- 1

   select {
   case <-exitChan:
      fmt.Println("end")
   }
}