2016-03-07 36 views
5

Jeśli duża struktura jest wysyłana przez kanał w Go, czy jest faktycznie kopiowana między goroutines?Czy struktura jest faktycznie kopiowana między goroutinami, jeśli została wysłana przez kanał Golang?

Na przykład w poniższym kodzie skopiuje wszystkie dane largeStruct między producentem goroutines a konsumentem?

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++ 
     } 
    } 
} 

Playground: http://play.golang.org/p/fawEQnSDwB

+2

Alternatywnie, jeśli struktura zawierała wycinek, '[] int ', efekt przekazania segmentu (a zatem struktury) przez wartość nie skopiowałby wewnętrznej tablicy. Nie mówię, że to jest twoja odpowiedź. –

Odpowiedz

11

Tak, wszystko jest kopią w Go, można łatwo obejść, że przez zmianę kanału użyć wskaźnika (aka chan *largeStruct).

// demo: http://play.golang.org/p/CANxwt8s2B

Jak widać, wskaźnik do v.buf jest inna w każdym przypadku, ale jeśli go zmienić na chan *largeStruct, te wskaźniki będą takie same.

@LucasJones warunkiem trochę łatwiejsze do naśladowania przykład: https://play.golang.org/p/-VFWCgOnh0

Jak @nos wskazał, istnieje potencjał wyścig jeśli zmodyfikować wartość w obu goroutines po wysłaniu go.

+3

Oto demonstracja placów zabaw obu typów kanałów: https://play.golang.org/p/-VFWCgOnh0 –

+0

@LucasJones Dodam twój przykład do posta, aby uzyskać lepszą widoczność. – OneOfOne

+2

Pamiętaj tylko o potencjalnych warunkach wyścigu, jeśli wysyłasz tylko wskaźnik. Nie chcesz skończyć z obu gorankinami mieszającymi się z tą samą strukturą – nos

4

The Go Programming Language Specification

Send statements

Oświadczenie wyślij wysyła wartość na kanale. Wyrażenie kanału musi być typu kanału, kierunek kanału musi umożliwiać wysyłanie operacji , a typ wysyłanej wartości musi być przypisany do typu elementu kanału.

Jest to kopia, ponieważ wartość jest wysyłana do kanału przez przypisanie do typu elementu kanału. Jeśli wartością jest struct, to struktura jest kopiowana. Jeśli wartość jest wskaźnikiem do struct, to wskaźnik do struktury jest kopiowany.