在渠道中尝试几个实验时,我想到了以下代码:
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”后它停止了。
有人可以让我知道这种行为的原因吗?
还有这样的代码吗,例行程序在频道上侦听,创建一个新的保险箱?
答案 0 :(得分:2)
在Go中,for
语句在循环开始之前评估range
右侧的值。
这意味着更改range
右侧变量的值将不起作用。因此,在您的代码中,在变式A中,msg
在原始渠道中不断迭代,并且从未改变。在Varaint B中,它按预期工作,因为每次迭代都在评估通道。
这个概念有些棘手。这并不意味着您无法修改slice
右侧的map
或range
的项。如果您深入研究它,您会发现在Go语言中,map
和slice
存储了一个指针,并且修改其项不会更改该指针,因此它具有效果。
在array
的情况下更加棘手。修改array
右侧range
的 item 无效。这是由于Go将数组存储为值的机制。
答案 1 :(得分:1)
从通道发送和读取并不需要 进行互斥保护:它们由自己作为同步原语(这是主要思想之一)
变体A和B之间没有区别,因为您没有关闭通道。但是...
在迭代旧频道时将新频道分配到strChannel
是错误的。不要那样做甚至没有B变体。将range strChannel
视为“请在当前存储在变量strChannel
中的通道中的值范围内”。此范围将“在原始频道上继续”,并且将新频道存储在相同的变量中不会更改此范围。避免这样的代码!