《Go语言圣经》关闭一个channel

《Go语言圣经》关闭一个channel

func main() {
    naturals := make(chan int)
    squares := make(chan int)

    // Counter
    go func() {
        for x := 0; x < 100; x++ {
            naturals <- x
        }
        close(naturals)
    }()

    // Squarer
    go func() {
        for x := range naturals {
            squares <- x * x
        }
        close(squares)
    }()

    // Printer (in main goroutine)
    for x := range squares {
        fmt.Println(x)
    }
}

  • 在Go语言中,当一个channel被关闭后,已经发送到该channel中的数据仍然可以被正常接收,直到所有数据都被处理完毕。
  • 试图重复关闭一个channel将导致panic异常,试图关闭一个nil值的channel也将导致panic异常。关闭一个channels还会触发一个广播机制,

详细解释

在你的代码中:

  1. Counter协程naturals channel发送0到99的整数,然后关闭该channel
  2. Squarer协程使用for x := range naturals循环从naturals接收数据
  3. naturals被关闭时
    • 已经发送到naturals中的数据(0到99)仍然会被Squarer协程正常接收
    • for ... range循环会继续处理这些数据,直到所有数据都被处理完毕
    • 只有当所有数据都被接收后,for ... range循环才会退出

关键点

  • 关闭channel不会影响已发送的数据:关闭操作只是阻止后续的数据发送,不会影响已经在channel中的数据
  • for ... range循环会处理所有已发送的数据:无论channel是否关闭,循环都会继续执行,直到所有数据被接收
  • 关闭是一种信号:关闭channel是向接收方发送一个信号,表示"不会再有新数据了",但已有的数据仍然有效

验证代码

以下代码可以帮助你验证这个过程:

package main

import "fmt"

func main() {
    naturals := make(chan int)
    squares := make(chan int)

    // Counter
    go func() {
        for x := 0; x < 5; x++ {
            naturals <- x
            fmt.Println("Counter sent:", x)
            // 添加延迟以便观察执行顺序
            if x == 2 {
                close(naturals)
                fmt.Println("Counter closed naturals")
            }
        }
    }()

    // Squarer
    go func() {
        for x := range naturals {
            squares <- x * x
            fmt.Println("Squarer received:", x, "sending:", x*x)
        }
        close(squares)
        fmt.Println("Squarer closed squares")
    }()

    // Printer
    for x := range squares {
        fmt.Println("Printer received:", x)
    }
    fmt.Println("Done")
}

输出示例

Counter sent: 0
Squarer received: 0 sending: 0
Printer received: 0
Counter sent: 1
Squarer received: 1 sending: 1
Printer received: 1
Counter sent: 2
Squarer received: 2 sending: 4
Printer received: 4
Counter closed naturals
Counter sent: 3
Squarer received: 3 sending: 9
Printer received: 9
Counter sent: 4
Squarer received: 4 sending: 16
Printer received: 16
Squarer closed squares
Done

总结

  • 关闭channel后,已发送的数据仍然会被接收:在你的例子中,即使naturals被关闭,Squarer协程仍然会接收并处理0到99的所有数据
  • for ... range是处理channel的安全方式:它会自动处理关闭状态,确保所有数据都被处理
  • 这是Go语言并发模型的设计亮点:简洁、安全,避免了常见的并发错误
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值