侦听频道并进行循环处理时重写频道

时间:2018-07-02 13:13:03

标签: go channel

在渠道中尝试几个实验时,我想到了以下代码:

var strChannel = make(chan string, 30)
var mutex = &sync.Mutex{}

func main() {

    go sampleRoutine()

    for i := 0; i < 10; i++ {
        mutex.Lock()
        strChannel <- strconv.FormatInt(int64(i), 10)
        mutex.Unlock()
        time.Sleep(1 * time.Second)
    }

    time.Sleep(10 * time.Second)
}

func sampleRoutine() {
/*  A: for msg := range strChannel{*/
/*  B: for {
        msg := <-strChannel*/
        log.Println("got message ", msg, strChannel)
        if msg == "3" {
            mutex.Lock()
            strChannel = make(chan string, 20)
            mutex.Unlock()
        }
    }
}

基本上,这里是在收听给定频道时,我是在特定条件下(此处为msg == 3)将频道变量分配给新频道。

当我使用注释块B中的代码时,它可以按预期工作,即,循环移至新创建的通道并打印4-10。

但是我认为注释块A只是写循环的另一种方式不起作用,即在打印“ 3”后它停止了。

有人可以让我知道这种行为的原因吗?

还有这样的代码吗,例行程序在频道上侦听,创建一个新的保险箱?

2 个答案:

答案 0 :(得分:2)

在Go中,for语句在循环开始之前评估range右侧的值。

这意味着更改range右侧变量的值将不起作用。因此,在您的代码中,在变式A中,msg在原始渠道中不断迭代,并且从未改变。在Varaint B中,它按预期工作,因为每次迭代都在评估通道。

这个概念有些棘手。这并不意味着您无法修改slice右侧的maprange。如果您深入研究它,您会发现在Go语言中,mapslice存储了一个指针,并且修改其项不会更改该指针,因此它具有效果。

array的情况下更加棘手。修改array右侧range item 无效。这是由于Go将数组存储为值的机制。

游乐场示例:https://play.golang.org/p/wzPfGHFYrnv

答案 1 :(得分:1)

  1. 从通道发送和读取并不需要 进行互斥保护:它们由自己作为同步原语(这是主要思想之一)

  2. 变体A和B之间没有区别,因为您没有关闭通道。但是...

  3. 在迭代旧频道时将新频道分配到strChannel是错误的。不要那样做甚至没有B变体。将range strChannel视为“请在当前存储在变量strChannel中的通道中的值范围内”。此范围将“在原始频道上继续”,并且将新频道存储在相同的变量中不会更改此范围。避免这样的代码!