面试题答案
一键面试不带缓冲区的chan(无缓冲通道)
- 通信机制:
- 无缓冲通道在发送(
<-
)和接收(<-
)操作时,二者是同步进行的。也就是说,当一个 goroutine 向无缓冲通道发送数据时,它会阻塞,直到另一个 goroutine 从该通道接收数据。同样,当一个 goroutine 从无缓冲通道接收数据时,它也会阻塞,直到有其他 goroutine 向该通道发送数据。 - 这种机制保证了数据的发送和接收是原子性的,并且可以用于 goroutine 之间的同步。
- 无缓冲通道在发送(
- 示例:
package main
import (
"fmt"
)
func main() {
ch := make(chan int)
go func() {
fmt.Println("子 goroutine 准备发送数据")
ch <- 42
fmt.Println("子 goroutine 数据发送完成")
}()
fmt.Println("主 goroutine 准备接收数据")
data := <-ch
fmt.Printf("主 goroutine 接收到数据: %d\n", data)
}
在这个例子中,主 goroutine 会阻塞在 <-ch
这一行,直到子 goroutine 执行 ch <- 42
发送数据。同样,子 goroutine 会阻塞在 ch <- 42
这一行,直到主 goroutine 执行 <-ch
接收数据。
带缓冲区的chan(有缓冲通道)
- 通信机制:
- 有缓冲通道允许在没有接收者的情况下,先发送一定数量的数据到通道中,这个数量就是缓冲区的大小。只有当通道的缓冲区满了,再进行发送操作才会阻塞;同样,只有当通道的缓冲区为空时,接收操作才会阻塞。
- 有缓冲通道更侧重于数据的异步传递,而不是同步。
- 缓冲区大小对chan操作的影响示例:
package main
import (
"fmt"
)
func main() {
ch := make(chan int, 2)
fmt.Println("主 goroutine 准备发送数据")
ch <- 1
ch <- 2
fmt.Println("主 goroutine 数据发送完成")
fmt.Println("主 goroutine 准备接收数据")
data1 := <-ch
data2 := <-ch
fmt.Printf("主 goroutine 接收到数据: %d, %d\n", data1, data2)
}
在这个例子中,通道 ch
的缓冲区大小为2。主 goroutine 可以连续发送两个数据而不会阻塞,因为缓冲区足够容纳这两个数据。如果将缓冲区大小改为1,那么 ch <- 2
这一行就会阻塞,直到有接收者从通道中取走一个数据,腾出空间。
总结来说,无缓冲通道用于同步 goroutine,有缓冲通道用于异步数据传递,缓冲区大小决定了通道在阻塞发送操作前能容纳的数据量。