2016-03-07 8 views
5

Goのチャンネルで大きな構造体が送信された場合、実際にはgoroutines間でコピーされますか?例えば、以下のコードでは、実際にゴルーチン生産者と消費者の間で、すべてのlargeStructデータをコピー構造体は実際にGolangチャネルで送信された場合、ゴルーチン間でコピーされますか?

を行くのだろうか?

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

+2

また、構造体にスライス '[] int'が含まれている場合、スライス(したがって構造体)を値渡しすると内部配列がコピーされません。私はそれがあなたの答えだと言っているわけではありません。 –

答えて

11

はい、すべてはあなたが簡単にポインタ(別名chan *largeStruct)を使用するチャンネルを変更することにより、その回避することができ、移動中にコピーです。

//デモ:http://play.golang.org/p/CANxwt8s2B

あなたが見ることができるように、v.bufへのポインタは、あなたがchan *largeStructに変更した場合ただし、ポインタが同じになり、それぞれのケースで異なっています。

@LucasJonesは一例に従うことを少し簡単に提供:https://play.golang.org/p/-VFWCgOnh0

@nosが指摘したように、あなたがそれを送った後、両方のゴルーチンで値を変更した場合の潜在的レースがあります。 The Go Programming Language Specification

Send statements

+3

ここでは、両方のタイプのチャンネルの遊び場のデモンストレーションがあります:https://play.golang.org/p/-VFWCgOnh0 –

+0

@LucasJonesより良い視認性のためにあなたの例を投稿に追加します。 – OneOfOne

+2

ポインタだけを送信している場合は、潜在的な競合状態に気をつけてください。あなたは両方のgoroutinesが同じ構造体を使いこなすことになりたくない – nos

4

送信文は、チャネル上の値を送信します。チャネル式 は、チャネル型である必要があり、チャネル方向は 送信操作を許可する必要があり、その値の型は チャネルの要素型に割り当て可能でなければなりません送信します。

値はチャネルの要素タイプへの割り当てによってチャネルに送信されるため、コピーされます。値が構造体の場合は、構造体がコピーされます。値が構造体へのポインタであれば、構造体へのポインタがコピーされます。

関連する問題