Действительно ли структура копируется между горутинами, если она отправляется по каналу Golang?

Если большая структура отправляется по каналу в Go, действительно ли она копируется между горутинами?

Например, в приведенном ниже коде будет ли Go фактически копировать все данные largeStruct между производителем и потребителем горутин?

package main

import (
    "fmt"
    "sync"
)

type largeStruct struct {
    buf [10000]int
}

func main() {
    ch := make(chan largeStruct)
    wg := &sync.WaitGroup{}
    wg.Add(2)
    go consumer(wg, ch)
    go producer(wg, ch)
    wg.Wait()
}

func producer(wg *sync.WaitGroup, output chan<- largeStruct) {
    defer wg.Done()
    for i := 0; i < 5; i++ {
        fmt.Printf("producer: %d\n", i)
        output <- largeStruct{}
    }
    close(output)
}

func consumer(wg *sync.WaitGroup, input <-chan largeStruct) {
    defer wg.Done()
    i := 0
LOOP:
    for {
        select {
        case _, ok := <-input:
            if !ok {
                break LOOP
            }
            fmt.Printf("consumer: %d\n", i)
            i++
        }
    }
}

Игровая площадка: http://play.golang.org/p/fawEQnSDwB


person Everton    schedule 07.03.2016    source источник
comment
В качестве альтернативы, если структура содержит срез, `[]int', эффект передачи среза (и, следовательно, структуры) по значению не приведет к копированию внутреннего массива. Однако я не говорю, что это ваш ответ.   -  person Nathan Cooper    schedule 07.03.2016


Ответы (2)


Да, в Go все является копией, вы можете легко обойти это, изменив канал на использование указателя (также известного как chan *largeStruct).

// демо: http://play.golang.org/p/CANxwt8s2B

Как видите, указатель на v.buf в каждом случае разный, однако, если вы измените его на chan *largeStruct, указатели будут одинаковыми.

@LucasJones предоставил немного более простой пример: https://play.golang.org/p/-VFWCgOnh0

Как указал @nos, существует потенциальная гонка, если вы измените значение в обеих горутинах после его отправки.

person OneOfOne    schedule 07.03.2016
comment
Вот демонстрация обоих типов каналов: play.golang.org/p/-VFWCgOnh0 - person Lucas Jones; 07.03.2016
comment
@LucasJones Я добавлю ваш пример в пост для лучшей наглядности. - person OneOfOne; 07.03.2016
comment
Просто помните о потенциальных условиях гонки, если вы отправляете только указатель. Вы не хотите, чтобы обе горутины возились с одной и той же структурой. - person nos; 07.03.2016

Спецификация языка программирования Go

Отправить отчеты

Оператор отправки отправляет значение в канал. Выражение канала должно иметь тип канала, направление канала должно разрешать операции отправки, а тип отправляемого значения должен назначаться типу элемента канала.

Это копия, потому что значение отправляется в канал путем присвоения типу элемента канала. Если значение является структурой, то структура копируется. Если значение является указателем на структуру, то копируется указатель на структуру.

person peterSO    schedule 07.03.2016