2016-03-07 17 views
5

Nếu một cấu trúc lớn được gửi qua một kênh trong Go, nó có thực sự được sao chép giữa các goroutine không?Cấu trúc có thực sự được sao chép giữa các goroutines nếu được gửi qua kênh Golang không?

Ví dụ: trong mã bên dưới, Go thực sự sẽ sao chép tất cả dữ liệu bigStruct giữa nhà sản xuất và người tiêu dùng goroutines?

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

Cách khác, nếu cấu trúc chứa một slice, '[] int ', hiệu ứng truyền slice (và do đó struct) theo giá trị sẽ không sao chép mảng nội bộ. Tôi không nói đó là câu trả lời của bạn. –

Trả lời

11

Vâng, mọi thứ là một bản sao tại Gò, bạn có thể dễ dàng làm việc xung quanh đó bằng cách thay đổi kênh để sử dụng một con trỏ (aka chan *largeStruct).

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

Như bạn có thể thấy, các con trỏ đến v.buf là khác nhau trong từng trường hợp, tuy nhiên nếu bạn thay đổi nó để chan *largeStruct, con trỏ sẽ giống nhau.

@LucasJones cung cấp dễ dàng hơn một chút để làm theo ví dụ: https://play.golang.org/p/-VFWCgOnh0

Như @nos chỉ ra, có một chủng tộc tiềm năng nếu bạn sửa đổi các giá trị trong cả goroutines sau khi gửi đi.

+3

Đây là bản trình diễn sân chơi của cả hai loại kênh: https://play.golang.org/p/-VFWCgOnh0 –

+0

@LucasJones Tôi sẽ thêm ví dụ của bạn vào bài đăng để có khả năng hiển thị tốt hơn. – OneOfOne

+2

Chỉ cần biết về các điều kiện chủng tộc tiềm năng nếu bạn chỉ gửi một con trỏ. Bạn không muốn kết thúc với cả hai goroutines rối tung với cùng một struct – nos

4

The Go Programming Language Specification

Send statements

Một gửi tuyên bố sẽ gửi một giá trị trên một kênh. Biểu thức kênh phải thuộc loại kênh, hướng kênh phải cho phép các hoạt động gửi và loại giá trị được gửi phải được gán cho loại yếu tố của kênh.

Đó là bản sao vì giá trị được gửi tới kênh bằng cách gán cho loại phần tử của kênh. Nếu giá trị là một cấu trúc, thì cấu trúc được sao chép. Nếu giá trị là một con trỏ đến một cấu trúc, thì con trỏ tới cấu trúc được sao chép.

Các vấn đề liên quan