面试题答案
一键面试带缓冲区和不带缓冲区的channel在使用上的区别
- 不带缓冲区的channel:
- 发送操作(
<-
)和接收操作(<-
)会阻塞,直到对应的接收方或发送方准备好。这意味着当一个goroutine向一个不带缓冲区的channel发送数据时,它会被阻塞,直到另一个goroutine从这个channel接收数据。同样,当一个goroutine从一个不带缓冲区的channel接收数据时,它会被阻塞,直到有另一个goroutine向这个channel发送数据。 - 常用于实现同步通信,确保数据的发送和接收是一对一的,并且是同步进行的。
- 发送操作(
- 带缓冲区的channel:
- 发送操作不会立即阻塞,除非缓冲区已满。接收操作也不会立即阻塞,除非缓冲区为空。
- 缓冲区的大小决定了可以在不阻塞的情况下发送多少个数据。例如,
ch := make(chan int, 5)
创建了一个可以容纳5个int
类型数据的带缓冲区的channel。 - 常用于解耦发送方和接收方,允许一定程度的异步操作。
示例代码
package main
import (
"fmt"
"sync"
)
func worker(id int, done chan struct{}, wg *sync.WaitGroup) {
defer wg.Done()
<-done
fmt.Printf("Goroutine %d received signal and is doing task\n", id)
}
func main() {
var wg sync.WaitGroup
done := make(chan struct{}, 5)
for i := 1; i <= 5; i++ {
wg.Add(1)
go worker(i, done, &wg)
}
for i := 0; i < 5; i++ {
done <- struct{}{}
}
close(done)
wg.Wait()
}
在上述代码中:
- 我们创建了一个带缓冲区的
done
channel,缓冲区大小为5。 worker
函数是每个goroutine执行的函数,它等待从done
channel接收到信号,然后打印自己的编号。- 在
main
函数中,我们创建了5个goroutine,并使用sync.WaitGroup
来等待所有goroutine完成。 - 通过向
done
channel发送5个信号,通知所有goroutine开始执行任务,最后关闭done
channel,并等待所有goroutine完成。