使用切片类型的输入和输出通道执行并发工作程序例程

I am relatively new to the Go language. Even though I don't hope so, I maybe bother you with a silly question. My apologies upfront, just in case...

Here's my example: I defined a worker() function which is called from main() as a set of concurrent Go routines. Input and output data is provided via an input and an output channel both of slice type []int. In one case everything works as expected, in the other case the result is faulty. See the comments in the code and the program output below the code.

Honestly, I don't see the actual difference between both code variants. What did I miss here? Thank you for any advice!

package main

import "fmt"
import "runtime"

func worker(x_ch <-chan []int, y_ch chan<- []int, wid int) {

    for x := range x_ch {
        y := x
        fmt.Println("   worker", wid, "x:", x)
        fmt.Println("   worker", wid, "y:", y)
        y_ch <- y
    }
}

func main() {

    n_workers := runtime.NumCPU()
    n_len := 4
    n_jobs := 4
    x := make([]int, n_len)
    x_ch := make(chan []int, 10)
    y_ch := make(chan []int, 10)

    for j := 0; j < n_workers; j++ { go worker(x_ch, y_ch, j) }

    for k := 0; k < n_jobs; k++ {

//      variant 1: works!
        x = []int{k, k, k, k}

//      variant 2: doesn't work!
//      for i := range x { x[i] = k }

        fmt.Println("main x:", k, x)
        x_ch <- x
    }

    close(x_ch)

    for i := 0; i < n_jobs; i++ {
        z := <- y_ch
        fmt.Println("       main y:", i, z)
    }
}

Correct output (variant 1):

main x: 0 [0 0 0 0]
main x: 1 [1 1 1 1]
main x: 2 [2 2 2 2]
main x: 3 [3 3 3 3]
   worker 3 x: [3 3 3 3]
   worker 3 y: [3 3 3 3]
   worker 2 x: [2 2 2 2]
   worker 2 y: [2 2 2 2]
   worker 1 x: [0 0 0 0]
   worker 1 y: [0 0 0 0]
   worker 0 x: [1 1 1 1]
   worker 0 y: [1 1 1 1]
       main y: 0 [3 3 3 3]
       main y: 1 [2 2 2 2]
       main y: 2 [0 0 0 0]
       main y: 3 [1 1 1 1]

Wrong output (variant 2):

main x: 0 [0 0 0 0]
main x: 1 [1 1 1 1]
main x: 2 [2 2 2 2]
main x: 3 [3 3 3 3]
   worker 3 x: [3 3 3 3]
   worker 3 y: [3 3 3 3]
       main y: 0 [3 3 3 3]
   worker 0 x: [2 2 2 2]
   worker 0 y: [3 3 3 3]
       main y: 1 [3 3 3 3]
   worker 1 x: [1 1 1 1]
   worker 1 y: [3 3 3 3]
       main y: 2 [3 3 3 3]
   worker 2 x: [3 3 3 3]
   worker 2 y: [3 3 3 3]
       main y: 3 [3 3 3 3]

The difference is that in variant 1, you're sending a different slice every time, whereas in variant 2, you're sending the same slice every time (the one created above the for loops). Without creating a new slice, you're just setting the elements of the same slice to different values, so the goroutines see whatever values happen to be in the slice when they look at it. In variant 2, main will always see [3 3 3 3] because that's the final value after you've gone through the loop 4 times. The value of a slice object contains a reference to the underlying elements, not the elements themselves. There's a good explanation of slices here.

Thanks a lot for your explanation, now I see where the problem is. I added some debug code to output the pointer addresses and the result is (with slighty reformatted output):

Variant 1:

main 0 x=[0 0 0 0] &x=0x1830e180 &x[0]=0x1830e1e0
main 1 x=[1 1 1 1] &x=0x1830e180 &x[0]=0x1830e230
main 2 x=[2 2 2 2] &x=0x1830e180 &x[0]=0x1830e270
main 3 x=[3 3 3 3] &x=0x1830e180 &x[0]=0x1830e2a0
    worker 3 x=[3 3 3 3] &x=0x1830e1d0 &x[0]=0x1830e2a0
    worker 3 y=[3 3 3 3] &y=0x1830e2e0 &y[0]=0x1830e2a0
        main 0 y=[3 3 3 3] &y=0x1830e2d0 &y[0]=0x1830e2a0
    worker 0 x=[0 0 0 0] &x=0x1830e1a0 &x[0]=0x1830e1e0
    worker 0 y=[0 0 0 0] &y=0x1830e370 &y[0]=0x1830e1e0
        main 1 y=[0 0 0 0] &y=0x1830e360 &y[0]=0x1830e1e0
    worker 1 x=[1 1 1 1] &x=0x1830e1b0 &x[0]=0x1830e230
    worker 1 y=[1 1 1 1] &y=0x1830e400 &y[0]=0x1830e230
        main 2 y=[1 1 1 1] &y=0x1830e3f0 &y[0]=0x1830e230
    worker 2 x=[2 2 2 2] &x=0x1830e1c0 &x[0]=0x1830e270
    worker 2 y=[2 2 2 2] &y=0x1830e480 &y[0]=0x1830e270
        main 3 y=[2 2 2 2] &y=0x1830e470 &y[0]=0x1830e270

Variant 2:

main 0 x=[0 0 0 0] &x=0x1830e180 &x[0]=0x1830e190
main 1 x=[1 1 1 1] &x=0x1830e180 &x[0]=0x1830e190
main 2 x=[2 2 2 2] &x=0x1830e180 &x[0]=0x1830e190
main 3 x=[3 3 3 3] &x=0x1830e180 &x[0]=0x1830e190
    worker 3 x=[3 3 3 3] &x=0x1830e1d0 &x[0]=0x1830e190
    worker 3 y=[3 3 3 3] &y=0x1830e2a0 &y[0]=0x1830e190
        main 0 y=[3 3 3 3] &y=0x1830e290 &y[0]=0x1830e190
    worker 0 x=[3 3 3 3] &x=0x1830e1a0 &x[0]=0x1830e190
    worker 0 y=[3 3 3 3] &y=0x1830e330 &y[0]=0x1830e190
        main 1 y=[3 3 3 3] &y=0x1830e320 &y[0]=0x1830e190
    worker 1 x=[3 3 3 3] &x=0x1830e1b0 &x[0]=0x1830e190
    worker 1 y=[3 3 3 3] &y=0x1830e3c0 &y[0]=0x1830e190
        main 2 y=[3 3 3 3] &y=0x1830e3b0 &y[0]=0x1830e190
    worker 2 x=[3 3 3 3] &x=0x1830e1c0 &x[0]=0x1830e190
    worker 2 y=[3 3 3 3] &y=0x1830e440 &y[0]=0x1830e190
        main 3 y=[3 3 3 3] &y=0x1830e430 &y[0]=0x1830e190