MST

星途 面试题库

面试题:Go中基于缓冲与非缓冲通道实现复杂同步逻辑

给定一个场景:有一组任务,任务分为A、B两类,要求A类任务先执行一定数量(例如5个),然后B类任务才能开始执行,且B类任务执行完后,A类任务可以继续执行。请使用Go语言的缓冲通道和非缓冲通道来设计并实现这种复杂的同步逻辑,阐述设计思路,并说明选择不同通道类型的原因。
23.4万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

设计思路

  1. 使用缓冲通道实现
    • 缓冲通道用于控制A类任务的执行数量。当A类任务执行到一定数量(例如5个)时,向通道发送信号,B类任务开始执行。
    • 另一个非缓冲通道用于确保B类任务执行完成后,A类任务继续执行。
  2. 使用非缓冲通道实现
    • 非缓冲通道用于同步A类任务和B类任务的执行。A类任务执行一定数量后,通过非缓冲通道与B类任务进行同步,B类任务执行完后,再通过非缓冲通道通知A类任务继续执行。

代码实现

  1. 使用缓冲通道
package main

import (
    "fmt"
)

func main() {
    aTaskCount := 5
    aTaskDone := make(chan struct{}, aTaskCount)
    bTaskDone := make(chan struct{})

    // A类任务
    go func() {
        for i := 0; i < 10; i++ {
            fmt.Println("A类任务执行:", i)
            if i < aTaskCount {
                aTaskDone <- struct{}{}
            }
            if i >= aTaskCount {
                <-bTaskDone
            }
        }
    }()

    // B类任务
    go func() {
        for i := 0; i < aTaskCount; i++ {
            <-aTaskDone
        }
        fmt.Println("B类任务开始执行")
        // 模拟B类任务执行
        fmt.Println("B类任务执行完毕")
        bTaskDone <- struct{}{}
    }()

    select {}
}
  1. 使用非缓冲通道
package main

import (
    "fmt"
)

func main() {
    aTaskCount := 5
    aTaskDone := make(chan struct{})
    bTaskDone := make(chan struct{})

    // A类任务
    go func() {
        for i := 0; i < 10; i++ {
            fmt.Println("A类任务执行:", i)
            if i == aTaskCount {
                close(aTaskDone)
            }
            if i >= aTaskCount {
                <-bTaskDone
            }
        }
    }()

    // B类任务
    go func() {
        for i := 0; i < aTaskCount; i++ {
            <-aTaskDone
        }
        fmt.Println("B类任务开始执行")
        // 模拟B类任务执行
        fmt.Println("B类任务执行完毕")
        bTaskDone <- struct{}{}
    }()

    select {}
}

选择不同通道类型的原因

  1. 缓冲通道
    • 优点:缓冲通道可以在不阻塞发送操作的情况下,存储一定数量的值。在这个场景中,缓冲通道aTaskDone可以先存储A类任务执行的信号,直到达到设定的数量,这样A类任务可以继续执行而不会阻塞。
    • 适用场景:适用于需要一定数量的任务先执行,然后触发其他任务执行,并且在触发之前不需要立即同步的场景。
  2. 非缓冲通道
    • 优点:非缓冲通道在发送和接收操作上是同步的,发送操作会阻塞直到有接收者准备好接收数据,反之亦然。在这个场景中,非缓冲通道aTaskDone可以确保A类任务执行到一定数量后,才与B类任务进行同步,保证了任务执行的顺序。
    • 适用场景:适用于需要严格同步任务执行顺序,确保一个任务执行到某个阶段后,另一个任务才能开始执行的场景。