面试题答案
一键面试工作原理区别
- 无缓冲的Go channel:
- 无缓冲的channel在发送和接收操作时是同步的。当一个goroutine尝试向无缓冲的channel发送数据时,它会阻塞,直到另一个goroutine从该channel接收数据。同样,当一个goroutine尝试从无缓冲的channel接收数据时,它也会阻塞,直到有另一个goroutine向该channel发送数据。
- 它就像两个人面对面传递物品,必须等对方伸手来接,这边才能递出去,双方都要同步等待。
- 带缓冲的Go channel:
- 带缓冲的channel内部有一个缓冲区,可以在没有接收者的情况下,先将数据发送到缓冲区中。只有当缓冲区满了,再进行发送操作时才会阻塞。同理,只有当缓冲区为空,再进行接收操作时才会阻塞。
- 这好比是一个有一定容量的邮箱,在邮箱满之前,发送者可以一直往邮箱里放信,而接收者可以在邮箱有信时随时来取。
场景举例
- 无缓冲的Go channel适用场景:
- 同步场景:例如在一个生产者 - 消费者模型中,如果希望生产者和消费者严格同步,即生产者生产一个数据后,必须等待消费者处理完才能继续生产下一个。
package main import ( "fmt" ) func main() { ch := make(chan int) go func() { num := 10 fmt.Println("生产者准备发送数据:", num) ch <- num fmt.Println("生产者数据已发送") }() result := <-ch fmt.Println("消费者接收到数据:", result) }
- 信号传递:用于在goroutine之间传递信号,比如通知某个goroutine开始执行某个任务。
package main import ( "fmt" ) func main() { signal := make(chan struct{}) go func() { <-signal fmt.Println("接收到信号,开始执行任务") }() fmt.Println("发送信号") signal <- struct{}{} }
- 带缓冲的Go channel适用场景:
- 解耦生产者和消费者:如果生产者生产数据的速度比消费者处理数据的速度快,使用带缓冲的channel可以让生产者先将数据存入缓冲区,而不必立即等待消费者处理。
package main import ( "fmt" ) func main() { ch := make(chan int, 5) go func() { for i := 0; i < 10; i++ { ch <- i fmt.Println("生产者发送数据:", i) } close(ch) }() for num := range ch { fmt.Println("消费者接收到数据:", num) } }
- 临时数据存储:当需要在goroutine之间临时存储一些数据,并且不需要严格同步时,可以使用带缓冲的channel。例如在一个日志记录系统中,多个goroutine可以将日志信息发送到一个带缓冲的channel,由一个专门的日志写入goroutine从channel中读取并写入文件。