Golang实现交替打印

586 阅读2分钟

1. 交替打印数字和字母12AB34CD56EF78GH910IJ1112KL1314MN1516OP1718QR1920ST2122UV2324WX2526YZ2728

package main

import (
    "fmt"
    "sync"
)

var (
    numChan = make(chan struct{})
    alphaChan = make(chan struct{})
    wg sync.WaitGroup
)

func printNumber() {
    i := 1
    for {
        select {
        case <-numChan:
            fmt.Printf("%d", i)
            i++
            fmt.Printf("%d", i)
            i++
            alphaChan <- struct{}{}
        default:
            break
        }
    }
}

func printAlphabet() {
    c := 'A'
    for {
        select {
            case <-alphaChan:
                if c > 'Z' {
                    fmt.Println()
                    wg.Done() // 所有字母打印完成后通知主goroutine退出
                    return
                }
                fmt.Printf("%c", c)
                c++
                fmt.Printf("%c", c)
                c++
                numChan <- struct{}{}
            default:
                break
            }
    }
}

func main() {
    go printNumber()
    wg.Add(1)
    go printAlphabet()
    numChan <- struct{}{} // 启动数字打印
    wg.Wait()
}

2. 交替打印0~100奇数和偶数

package main

import (
    "fmt"
    "sync"
)

func printOdd(oddCh, evenCh chan int, wg *sync.WaitGroup) {
    defer wg.Done()
    for {
        select {
        case num := <-oddCh:
            if num > 100 {
                evenCh <- num + 1 // 通知printEven结束
                return
            }
            fmt.Println("Odd:", num)
            evenCh <- num + 1
        default:
            break
        }
    }
}

func printEven(oddCh, evenCh chan int, wg *sync.WaitGroup) {
    defer wg.Done()
    for {
        select {
        case num := <-evenCh:
            if num > 100 {
                fmt.Println("End")
                return
            }
            fmt.Println("Even:", num)
            oddCh <- num + 1
        default:
            break
        }
    }
}

func main() {
    var wg sync.WaitGroup
    oddCh, evenCh := make(chan int), make(chan int)
    wg.Add(2)
    go printOdd(oddCh, evenCh, &wg)
    go printEven(oddCh, evenCh, &wg)
    oddCh <- 1
    wg.Wait()
    close(oddCh)
    close(evenCh)
}

3. 三个goroutine交替打印ABC

package main

import (
    "fmt"
    "sync"
)

const N = 10

func main() {
    var wg sync.WaitGroup
    ch1, ch2, ch3 := make(chan struct{}), make(chan struct{}), make(chan struct{})
    wg.Add(3)
    
    go func(s string) {
        defer wg.Done()
        for i := 0; i < N; i++ {
            <-ch1
            fmt.Print(s)
            ch2 <- struct{}{}
        }
    }("A")
    
    go func(s string) {
        wg.Done()
        for i := 0; i < N; i++ {
            <-ch2
            fmt.Print(s)
            ch3 <- struct{}{}
        }
    }("B")
    
    go func(s string) {
        wg.Done()
        for i := 0; i < N; i++ {
            <-ch3
            fmt.Print(s)
            ch1 <- struct{}{}
        }
    }("C")
    
    ch1 <- struct{}{}
    wg.Wait()
}

4. N个goroutine交替打印0~100

package main

import (
    "fmt"
    "sync"
)

const N = 10

func main() {
    var wg sync.WaitGroup
    chQueue := make([]chan int, N)
    for i := 0; i < N; i++ {
        chQueue[i] = make(chan int)
    }
    
    for i := 0; i < N; i++ {
        wg.Add(1)
        go func(id int, curCh, nextCh chan int) {
            defer wg.Done()
            for {
                num, ok := <-curCh
                if !ok || num > 100 {
                    if id != N-1 { // 如果不是最后一个goroutine,将结束数字发送到下个channel
                        nextCh <- num
                    }
                    return
                }
                fmt.Printf("第%d个协程打印的数字%d\n", id, num)
                nextCh <- num + 1
            }
        }(i, chQueue[i], chQueue[(i+1)%N])
    }
    
    chQueue[0] <- 1
    wg.Wait()
}

在使用channel时需要注意避免死锁,这通常发生在以下情况:

  • 向一个没有接收者的无缓冲channel发送数据。
  • 从一个没有发送者的channel接收数据。
  • 缓冲channel满了之后继续发送数据,且没有接收者。
  • 缓冲channel空了之后继续接收数据,且没有发送者。