面试题答案
一键面试通道基本原理
- 类型声明:
在Go语言中,通道是一种类型,用于在不同的goroutine之间进行通信。其声明语法如下:
通道类型可以是带缓冲的或无缓冲的。带缓冲通道在创建时指定缓冲大小,例如var ch chan int // 声明一个可以传递int类型数据的通道 ch := make(chan int) // 使用make函数创建一个可以传递int类型数据的通道
ch := make(chan int, 10)
,表示该通道可以缓存10个int类型的数据。无缓冲通道则没有缓存,发送操作会阻塞直到有接收操作准备好接收数据。 - 发送操作:
使用
<-
操作符向通道发送数据。例如:
如果通道是无缓冲的,当执行发送操作时,如果没有接收者准备好接收数据,发送操作会阻塞当前goroutine,直到有接收者接收数据。如果通道是有缓冲的,当通道未满时,发送操作不会阻塞;当通道已满时,发送操作会阻塞,直到有接收者接收数据,腾出空间。ch <- 10 // 将10发送到通道ch
- 接收操作:
同样使用
<-
操作符从通道接收数据。有两种接收方式:
当从无缓冲通道接收数据时,如果没有数据可接收,接收操作会阻塞当前goroutine,直到有数据发送进来。从有缓冲通道接收数据时,如果通道中有数据,接收操作不会阻塞;如果通道为空,接收操作会阻塞,直到有数据发送进来。data := <-ch // 从通道ch接收数据,并赋值给data data, ok := <-ch // 从通道ch接收数据,并通过ok判断通道是否关闭。如果通道已关闭且无数据可接收,ok为false
示例代码
package main
import (
"fmt"
)
func producer(ch chan int) {
for i := 0; i < 5; i++ {
ch <- i
fmt.Printf("Produced: %d\n", i)
}
close(ch) // 生产完成后关闭通道
}
func consumer(ch chan int) {
for data := range ch {
fmt.Printf("Consumed: %d\n", data)
}
}
func main() {
ch := make(chan int)
go producer(ch)
go consumer(ch)
// 防止主函数退出
select {}
}
在上述代码中:
producer
函数是一个goroutine,它生成数据并通过通道ch
发送出去,在生产完5个数据后关闭通道。consumer
函数也是一个goroutine,它使用for... range
循环从通道ch
接收数据,当通道关闭且无数据可接收时,循环结束。- 在
main
函数中,创建了通道ch
,并启动了producer
和consumer
两个goroutine,通过通道实现了两个goroutine之间的数据安全传递和简单同步。select {}
语句用于防止主函数退出,确保两个goroutine有足够时间完成任务。