面试题答案
一键面试场景一:向无缓冲管道发送数据时,接收端未准备好
- 场景描述:
- 无缓冲管道在发送数据时,必须立刻有对应的接收操作,否则发送操作就会阻塞。例如:
package main import ( "fmt" ) func main() { ch := make(chan int) ch <- 1 // 这里会阻塞,因为没有接收操作 fmt.Println("Send successfully") }
- 避免方法:
- 确保在发送数据前,接收端已准备好接收。可以先启动接收协程,例如:
package main import ( "fmt" ) func main() { ch := make(chan int) go func() { data := <-ch fmt.Println("Received:", data) }() ch <- 1 fmt.Println("Send successfully") }
场景二:从无缓冲管道接收数据时,发送端未准备好
- 场景描述:
- 当从无缓冲管道接收数据时,如果没有数据发送进来,接收操作会阻塞。例如:
package main import ( "fmt" ) func main() { ch := make(chan int) data := <-ch // 这里会阻塞,因为没有数据发送进来 fmt.Println("Received:", data) }
- 避免方法:
- 确保在接收数据前,发送端已发送数据。同样可以先启动发送协程,例如:
package main import ( "fmt" ) func main() { ch := make(chan int) go func() { ch <- 1 fmt.Println("Send successfully") }() data := <-ch fmt.Println("Received:", data) }
场景三:向已满的有缓冲管道发送数据
- 场景描述:
- 有缓冲管道有一定的容量,如果管道已满,再进行发送操作就会阻塞。例如:
package main import ( "fmt" ) func main() { ch := make(chan int, 2) ch <- 1 ch <- 2 ch <- 3 // 这里会阻塞,因为管道容量为2,已经满了 fmt.Println("Send successfully") }
- 避免方法:
- 可以通过检查管道是否已满来避免阻塞,使用
select
语句结合default
分支。例如:
package main import ( "fmt" ) func main() { ch := make(chan int, 2) ch <- 1 ch <- 2 select { case ch <- 3: fmt.Println("Send successfully") default: fmt.Println("Channel is full, cannot send") } }
- 可以通过检查管道是否已满来避免阻塞,使用
场景四:从已关闭且无数据的管道接收数据
- 场景描述:
- 当管道关闭且没有剩余数据时,接收操作会立即返回零值而不会阻塞。但如果程序逻辑依赖于管道持续有数据,可能会出现逻辑错误。例如:
package main import ( "fmt" ) func main() { ch := make(chan int) close(ch) data, ok := <-ch if!ok { fmt.Println("Channel is closed, no data") } else { fmt.Println("Received:", data) } }
- 避免方法:
- 在接收数据时,通过
ok
标志判断管道是否关闭,并且在关闭管道前确保所有数据都已发送完毕。例如:
package main import ( "fmt" ) func main() { ch := make(chan int) go func() { for i := 0; i < 3; i++ { ch <- i } close(ch) }() for { data, ok := <-ch if!ok { break } fmt.Println("Received:", data) } }
- 在接收数据时,通过