英文:
goroutine only passes half of values through channel
问题
我有一个文件:
package main
import "fmt"
func combinations(result chan []byte, len int, min byte, max byte) {
res := make([]byte,len)
for i := 0; i < len; i++ {
res[i] = min
}
result <- res
for true {
i := 0
for i = 0; i < len; i++ {
if res[i] < max {
res[i] = res[i] + 1;
break
} else {
res[i] = 32
}
}
result <- res
if(i == len) {
close(result)
return;
}
}
}
func main() {
combination_chan := make(chan []byte)
go combinations(combination_chan, 2, 0, 5)
for next_combination := range combination_chan {
fmt.Printf("%x\n",next_combination)
}
}
我期望它打印出在0和5之间的所有2个字节的可能组合,例如:
0000
0100
...
0001
...
0505
然而,它似乎跳过了每个其他值,并打印了相同的值两次,例如:
0100
0100
0300
0300
...
为什么会这样?我在result <- res
这行之前插入了打印语句,那些都是正确的。
英文:
I have a file:
package main
import "fmt"
func
combinations(result chan []byte, len int, min byte, max byte) {
res := make([]byte,len)
for i := 0; i < len; i++ {
res[i] = min
}
result <- res
for true {
i := 0
for i = 0; i < len; i++ {
if res[i] < max {
res[i] = res[i] + 1;
break
} else {
res[i] = 32
}
}
result <- res
if(i == len) {
close(result)
return;
}
}
}
func
main() {
combination_chan := make(chan []byte)
go combinations(combination_chan, 2, 0, 5)
for next_combination := range combination_chan {
fmt.Printf("%x\n",next_combination)
}
}
I expect this to print all possible combinations of 2 bytes between 0 and 5, IE:
0000
0100
...
0001
...
0505
However, it seems to skip every other value, and print the same value twice, IE:
0100
0100
0300
0300
...
Why would it be doing this? I've inserted prints before the 'result <- res' line, and those are all correct.
答案1
得分: 2
如果我们简化一下,Go语言中的切片(slice)基本上是指向数组的指针,所以通过通道传递一个你仍然拥有并且可以修改的切片,会导致数据竞争。
无法确定在将切片传递给通道之后,另一个goroutine从通道中读取切片之前,切片的内容是否被修改。
因此,你的整个算法会导致未定义的行为,因为你只是一遍又一遍地传递相同的内容并对其进行修改。
在你的情况下,一个解决方案是在通过通道发送之前复制切片:
buf := make([]byte, len(res))
copy(buf, res)
result <- buf
在这里可以看到它的运行结果:http://play.golang.org/p/ulLYy9Uqnp
另外,我不建议使用len
作为变量名,因为它可能与len()
内置函数冲突。
英文:
If we simplify a bit, a slice in Go is basically a pointer to an array, so by passing a slice that you still own and modify through a channel, you create a data race.
There is no telling if the contents of the slice are modified between the moment it is passed to the channel and the moment it is read from the channel by another goroutine.
So your whole algorithm leads to undefined behaviour, because you only pass the same contents over and over again while modifying them.
A solution in your case would be to copy the slice before sending it through the channel:
buf := make([]byte, len(res))
copy(buf, res)
result <- buf
See it running here: http://play.golang.org/p/ulLYy9Uqnp
Also, I don't recommend using len
as a variable name, because it can conflict with the len()
builtin function.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论