MST

星途 面试题库

面试题:Go语言中通道发送与接收数据的常见模式

在Go语言中,描述一下使用通道(channel)进行数据发送与接收的几种常见模式,例如单向通道的使用场景及代码示例,阻塞与非阻塞发送、接收的区别及如何实现。
18.1万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

1. 单向通道使用场景及代码示例

  • 使用场景:单向通道用于限制数据流动方向,比如只能发送(chan<-)或只能接收(<-chan)。常用于封装一个模块,只允许特定方向的数据操作,增强代码安全性和可读性。例如在生产者 - 消费者模型中,生产者向只能发送的通道发送数据,消费者从只能接收的通道读取数据。
  • 代码示例
package main

import (
    "fmt"
)

// 生产者函数,向只能发送的通道发送数据
func producer(ch chan<- int) {
    for i := 0; i < 5; i++ {
        ch <- i
    }
    close(ch)
}

// 消费者函数,从只能接收的通道读取数据
func consumer(ch <-chan int) {
    for val := range ch {
        fmt.Println("Received:", val)
    }
}

func main() {
    ch := make(chan int)
    go producer(ch)
    consumer(ch)
}

2. 阻塞与非阻塞发送、接收的区别及实现

  • 阻塞发送
    • 区别:当向通道发送数据时,如果通道已满(对于有缓冲通道)或没有接收者(对于无缓冲通道),发送操作会阻塞当前 goroutine,直到有接收者从通道接收数据(无缓冲通道)或通道有空闲空间(有缓冲通道)。
    • 实现
package main

import (
    "fmt"
)

func main() {
    ch := make(chan int, 1)
    ch <- 1
    fmt.Println("Sent 1")
    // 这里如果没有接收操作,下一行发送操作会阻塞
    ch <- 2
    fmt.Println("Sent 2")
}
  • 非阻塞发送
    • 区别:非阻塞发送不会阻塞当前 goroutine。如果通道已满(对于有缓冲通道)或没有接收者(对于无缓冲通道),发送操作会立即失败并返回。
    • 实现:通过使用 select 语句结合 default 分支实现。
package main

import (
    "fmt"
)

func main() {
    ch := make(chan int, 1)
    ch <- 1
    select {
    case ch <- 2:
        fmt.Println("Sent 2")
    default:
        fmt.Println("Send operation failed")
    }
}
  • 阻塞接收
    • 区别:当从通道接收数据时,如果通道为空(对于有缓冲通道)或没有发送者(对于无缓冲通道),接收操作会阻塞当前 goroutine,直到有发送者向通道发送数据。
    • 实现
package main

import (
    "fmt"
)

func main() {
    ch := make(chan int)
    go func() {
        ch <- 1
    }()
    val := <-ch
    fmt.Println("Received:", val)
}
  • 非阻塞接收
    • 区别:非阻塞接收不会阻塞当前 goroutine。如果通道为空(对于有缓冲通道)或没有发送者(对于无缓冲通道),接收操作会立即返回零值(如果通道类型是基本类型)和一个表示是否成功接收到数据的布尔值。
    • 实现:同样通过 select 语句结合 default 分支实现。
package main

import (
    "fmt"
)

func main() {
    ch := make(chan int)
    select {
    case val := <-ch:
        fmt.Println("Received:", val)
    default:
        fmt.Println("Receive operation failed")
    }
}