Golang close 函数
最后修改时间 2025 年 5 月 8 日
本教程将解释如何在 Go 中使用内置的 close 函数。我们将通过实际示例涵盖通道基础知识和正确的通道管理。
close 函数用于关闭 Go 中的通道。关闭通道表示不再向其发送值。这对于正确的通道清理和防止 goroutine 泄露至关重要。
在 Go 中,close 与通道一起使用,以表示发送操作的完成。关闭的通道在变空之前仍然可以读取,但向已关闭的通道发送数据会导致 panic。
基本通道关闭示例
close 最简单的用法是在发送完所有值后关闭通道。此示例演示了基本的通道关闭。
注意: 只有发送者应该关闭通道,接收者绝不能关闭。
package main
import "fmt"
func main() {
ch := make(chan int, 3)
ch <- 1
ch <- 2
ch <- 3
close(ch) // Close the channel after sending values
for num := range ch {
fmt.Println("Received:", num)
}
fmt.Println("Channel closed and drained")
}
发送三个值后关闭通道。range 循环会读取所有值,直到通道变空并关闭。这确保了正确的清理。
检测通道关闭
我们可以通过接收操作的第二个返回值来检测通道何时关闭。此示例显示了显式的已关闭通道检测。
package main
import "fmt"
func main() {
ch := make(chan string, 2)
ch <- "first"
ch <- "second"
close(ch)
for {
msg, ok := <-ch
if !ok {
fmt.Println("Channel closed")
break
}
fmt.Println("Received:", msg)
}
}
当通道关闭且为空时,ok 布尔值变为 false。此模式对于在复杂流程中进行显式已关闭通道检测很有用。
使用 goroutine 关闭通道
正确地使用 goroutine 关闭通道可以防止 goroutine 泄露。此示例显示了 goroutine 之间协调的通道关闭。
package main
import (
"fmt"
"time"
)
func worker(tasks <-chan int, done chan<- bool) {
for task := range tasks {
fmt.Println("Processing task", task)
time.Sleep(500 * time.Millisecond)
}
done <- true
}
func main() {
tasks := make(chan int, 3)
done := make(chan bool)
go worker(tasks, done)
for i := 1; i <= 3; i++ {
tasks <- i
}
close(tasks) // Signal no more tasks
<-done // Wait for worker to finish
fmt.Println("All tasks processed")
}
主 goroutine 在发送完毕后关闭 tasks 通道。worker goroutine 在检测到已关闭的通道时退出。这可以防止泄露。
关闭多个接收者
关闭通道可以同时通知多个接收者 goroutine。此示例演示了通过通道关闭进行的广播。
package main
import (
"fmt"
"sync"
)
func receiver(id int, ch <-chan int, wg *sync.WaitGroup) {
defer wg.Done()
for num := range ch {
fmt.Printf("Receiver %d got %d\n", id, num)
}
fmt.Printf("Receiver %d exiting\n", id)
}
func main() {
var wg sync.WaitGroup
ch := make(chan int)
for i := 1; i <= 3; i++ {
wg.Add(1)
go receiver(i, ch, &wg)
}
for i := 1; i <= 5; i++ {
ch <- i
}
close(ch) // Signal all receivers to exit
wg.Wait()
fmt.Println("All receivers exited")
}
关闭通道会导致所有三个接收者 goroutine 退出。WaitGroup 确保 goroutine 之间的正确同步。
防止来自已关闭通道的 panic
向已关闭的通道发送数据会导致 panic。此示例展示了如何安全地处理通道操作以防止 panic。
package main
import (
"fmt"
"sync"
)
func safeSend(ch chan<- int, value int, wg *sync.WaitGroup) {
defer wg.Done()
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered from panic:", r)
}
}()
ch <- value
}
func main() {
var wg sync.WaitGroup
ch := make(chan int, 1)
// First send works
wg.Add(1)
go safeSend(ch, 1, &wg)
// Close the channel
close(ch)
// Second send would panic but we recover
wg.Add(1)
go safeSend(ch, 2, &wg)
wg.Wait()
fmt.Println("Program completed safely")
}
safeSend 函数使用 recover 来处理潜在的 panic。此模式使通道操作在复杂系统中更加健壮。
来源
本教程通过正确的通道管理和清理的实际示例,介绍了 Go 中的 close 函数。