nil channel

nil channel的应用

(转自:https://blog.csdn.net/weixin_33834679/article/details/86026664

当未为channel分配内存时,channel就是nil channel,例如var ch1 chan int。nil channel会永远阻塞对该channel的读、写操作。

nil channel会阻塞对该channel的所有读、写。所以,可以将某个channel设置为nil,进行强制阻塞,对于select分支来说,就是强制禁用此分支。

以下是一个nil channel的示例:

package main
 
import (
    "fmt"
    "math/rand"
    "time"
)
 
// 不断向channel c中发送[0,10)的随机数
func send(c chan int) {
    for {
        c <- rand.Intn(10)
    }
}
 
func add(c chan int) {
    sum := 0
 
    // 1秒后,将向t.C通道发送时间点,使其可读
    t := time.NewTimer(1 * time.Second)
 
    for {
        // 一秒内,将一直选择第一个case
        // 一秒后,t.C可读,将选择第二个case
        // c变成nil channel后,两个case分支都将一直阻塞
        select {
        case input := <-c:
            // 不断读取c中的随机数据进行加总
            sum = sum + input
        case <-t.C:
            c = nil
            fmt.Println(sum)
        }
    }
}
 
func main() {
    c := make(chan int)
    go add(c)
    go send(c)
    // 给3秒时间让前两个goroutine有足够时间运行
    time.Sleep(3 * time.Second)
}

上面的示例中,send()向通道c不断发送10以内的随机整数,add()则在一秒内不断读取通道c中的数据并进行加总。一秒时间到后,t.C通道就会有数据,第二个case分支就会被选中,第二个case会让第一个case评估的channel变为nil channel,使得第一个case从此永久禁用,因为第二个case没有多余的数据可读,它也被永久禁用。总共3秒之后,main goroutine结束,程序结束。

如果不理解NewTimer(d),换成After(d)是一样的,After(d)和NewTime(d).C是等价的。

func add(c chan int) {
    sum := 0
    t := time.After(1 * time.Second)
    for {
        select {
        case val := <-c:
            sum = sum + val
        case <-t:
            c = nil
            fmt.Println(sum)
        }
    }
}

资源回收问题

(转自:https://blog.csdn.net/WK_SDU/article/details/91052121)

如何回收废掉的分支这部分资源占用,事实上,因为这部分代码是当前goroutine(执行for select)的不会执行该分支而已,因此不会为该分支分配资源(如内存,cpu等)。不正确的使用,如单纯的从nil channel读取数据就会阻塞住该goroutine,且该goroutine无法被回收(为什么?),从而造成资源泄露,如下图:

func main(){
   var ch chan int
   data:=<-ch
   //or:
   for v:=range ch{
      //some code in here
   }
}


这样的代码会使当前goroutine 永久阻塞 这是不正确的做法。

Go 语言中的 Channel 在进行读、写、关闭等操作时会有一些特殊的行为。下面我将分别介绍在 nil、关闭的 channel、有数据的 channel 进行读、写、关闭时的行为。 1. 对于 nilchannel 进行读写操作: 对于 nilchannel 进行读写操作会导致 Goroutine 阻塞,并且会在运行时抛出 panic 异常。因此,在使用 channel 时,一定要确保它不是 nil。 2. 对于关闭的 channel 进行读写操作: 如果一个 channel 已经被关闭,那么对它进行写操作会导致 panic 异常。而对于读操作,如果 channel 中还有数据,那么可以正常读取并返回数据。但如果 channel 中已经没有数据了,那么读取操作会返回一个零值,并且不会阻塞。因此,在使用 channel 时,一定要注意判断 channel 是否已经被关闭。 3. 对于有数据的 channel 进行读写操作: 对于有数据的 channel 进行写操作会阻塞当前 Goroutine,直到有其他 Goroutine 读取了数据。而对于读操作,如果 channel 中还有数据,那么可以正常读取并返回数据。但如果 channel 中已经没有数据了,那么读取操作会阻塞当前 Goroutine,直到有其他 Goroutine 写入了数据或者 channel 被关闭。如果 channel 被关闭了,那么读取操作会返回一个零值,并且不会阻塞。 总之,当对 channel 进行读写操作时,需要注意它的状态,避免出现不必要的阻塞或异常。同时,对于已经关闭的 channel,不应该再进行写操作,否则会导致 panic 异常。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值