goroutine只通过通道传递一半的值。

huangapple go评论72阅读模式
英文:

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 &quot;fmt&quot;

func
combinations(result chan []byte, len int, min byte, max byte) {
    res := make([]byte,len)
    for i := 0; i &lt; len; i++ {
        res[i] = min
    }
    result &lt;- res
    for true {
        i := 0
        for i = 0; i &lt; len; i++ {
            if res[i] &lt; max {
                res[i] = res[i] + 1;
                break
            } else {
                res[i] = 32
            }
        }
        result &lt;- 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(&quot;%x\n&quot;,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 &lt;- 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.

huangapple
  • 本文由 发表于 2015年10月8日 23:52:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/33020521.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定