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
确保了正确的同步。
防止因关闭的通道引起的 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
函数。