сбивающий с толку вывод при итерации golang небуферизованного канала - PullRequest
0 голосов
/ 26 апреля 2020

Я получаю сбивающий с толку вывод, когда перебираю golang небуферизованный канал. Канал определяется как chan []int. Затем я пу sh два среза на канал, [0 1] и [2 3]. Но когда я выбираю элемент из канала, я получаю [2 3] и [2 3]. почему это происходит?

package main

import "fmt"
import "sync"

func producer(jobs chan []int, wg *sync.WaitGroup) {
    defer wg.Done()

    a := make([]int, 2)
    index := 0
    for i := 0; i < 4; i++ {
        a[index] = i
        index++
        if index == 2 {
            index = 0
            fmt.Printf("a: %+v\n", a)
            jobs <- a
        }    
    }

    close(jobs)
}

func main() {
    var wg sync.WaitGroup
    wg.Add(1)
    jobs := make(chan []int, 2)
    go producer(jobs, &wg)
    for job := range jobs {
        fmt.Printf("job: %+v\n", job)
    }

    wg.Wait()
}

ожидаемый результат:

a: [0 1]
a: [2 3]
job: [0 1]
job: [2 3]

фактический результат:

a: [0 1]
a: [2 3]
job: [2 3]
job: [2 3]

Ответы [ 2 ]

2 голосов
/ 26 апреля 2020

Срез содержит указатель на резервный массив. Когда вы отправляете срез через канал, вы отправляете ссылку на этот резервный массив, поэтому на принимающей стороне, даже когда вы читаете срез несколько раз, вы фактически ссылаетесь на один и тот же общий резервный массив.

Вы можете создать новый фрагмент для каждой итерации и отправить его. Каждый срез будет иметь отдельный массив поддержки и будет работать так, как вы ожидаете.

0 голосов
/ 26 апреля 2020

Немного модифицировал вашу программу для лучшего чтения.

package main

import "fmt"
import "sync"

func producer(jobs chan []int, wg *sync.WaitGroup) {
    defer wg.Done()

    a := make([]int, 2)
    a[0] = 1
    a[1] = 2
            jobs <- a   //We are passing memory location of slice ( is nature of slice ), so the values changing next line will affect here too
    a[0] = 2
    a[1] = 3
           jobs <- a  


    close(jobs)
}

func main() {
    var wg sync.WaitGroup
    wg.Add(1)
    jobs := make(chan []int, 2)
    go producer(jobs, &wg)
    for job := range jobs {
        fmt.Printf("job: %+v\n", job)
    }

    wg.Wait()
}

Та же программа, которую я пробовал с массивом, тогда мы получим ожидаемый вами результат, см. Код ниже

package main

import "fmt"
import "sync"

func producer(jobs chan [2]int, wg *sync.WaitGroup) {
    defer wg.Done()

   var a[2]int
    a[0] = 1
    a[1] = 2
            jobs <- a   
    a[0] = 2
    a[1] = 3
           jobs <- a  


    close(jobs)
}

func main() {
    var wg sync.WaitGroup
    wg.Add(1)
    jobs := make(chan [2]int)
    go producer(jobs, &wg)
    for job := range jobs {
        fmt.Printf("job: %+v\n", job)
    }

    wg.Wait()
}

Playground Link - Программа с использованием Slice

Playground Link - Программа с использованием Array

Основное правило - слайсы передаются по ссылке

...