重写通道,同时监听它并进行循环处理
Rewrite channel while listening on it and for loop handling
在频道中尝试一些实验时,我想到了以下代码:
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”后它停止了。
有人可以告诉我这种行为的原因吗?
还有像这样的代码,其中一个例程监听一个频道,创建一个新的安全吗?
从通道发送和读取 不需要 需要互斥锁保护:它们由自己[=]充当同步原语25=](这是 sending/receiving 背后的主要思想之一)在频道上。
变体A和B没有区别,因为你没有关闭通道。但是...
在迭代旧频道的同时将新频道重新分配给 strChannel
是错误的。不要那样做。甚至没有 B 变体。将 range strChannel
视为 "please range over the values in the channel currently stored in the variable strChannel
"。这个范围将 "continue on the original channel" 并在同一个变量中存储一个新频道不会改变这一点。避免这样的代码!
在 Go 中,for
语句在循环开始之前计算 range
右侧的值。
也就是说改变range
右边的变量值不会有任何效果。因此,在您的代码中,在变体 A 中,msg
不断迭代原始通道并且从未改变。在 Varaint B 中,它按预期工作,因为每次迭代都会评估通道。
这个概念有点棘手。这并不意味着您不能修改 range
右侧 slice
或 map
的 项 。如果深入研究,你会发现在Go中,map
和slice
存储的是一个指针,修改它的item并不会改变那个指针,所以是有效果的。
在 array
的情况下更加棘手。修改 range
右侧的 array
的 item 没有任何效果。这是由于 Go 将数组存储为值的机制。
在频道中尝试一些实验时,我想到了以下代码:
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”后它停止了。
有人可以告诉我这种行为的原因吗?
还有像这样的代码,其中一个例程监听一个频道,创建一个新的安全吗?
从通道发送和读取 不需要 需要互斥锁保护:它们由自己[=]充当同步原语25=](这是 sending/receiving 背后的主要思想之一)在频道上。
变体A和B没有区别,因为你没有关闭通道。但是...
在迭代旧频道的同时将新频道重新分配给
strChannel
是错误的。不要那样做。甚至没有 B 变体。将range strChannel
视为 "please range over the values in the channel currently stored in the variablestrChannel
"。这个范围将 "continue on the original channel" 并在同一个变量中存储一个新频道不会改变这一点。避免这样的代码!
在 Go 中,for
语句在循环开始之前计算 range
右侧的值。
也就是说改变range
右边的变量值不会有任何效果。因此,在您的代码中,在变体 A 中,msg
不断迭代原始通道并且从未改变。在 Varaint B 中,它按预期工作,因为每次迭代都会评估通道。
这个概念有点棘手。这并不意味着您不能修改 range
右侧 slice
或 map
的 项 。如果深入研究,你会发现在Go中,map
和slice
存储的是一个指针,修改它的item并不会改变那个指针,所以是有效果的。
在 array
的情况下更加棘手。修改 range
右侧的 array
的 item 没有任何效果。这是由于 Go 将数组存储为值的机制。