2017-01-21 21 views
0

Я относительно новичок в языке Go. Хотя я и не надеюсь на это, я, возможно, буду беспокоить вас глупым вопросом. Мои извинения заранее, на всякий случай ...Выполнять параллельные рабочие процедуры с использованием входных и выходных каналов типа slice

Вот мой пример: Я определил функцию worker(), которая вызывается из main() как набор параллельных подпрограмм Go. Входные и выходные данные предоставляются через входной и выходной каналы как для slice type [] int. В одном случае все работает так, как ожидалось, в другом случае результат неисправен. См. Комментарии в коде и выходе программы под кодом.

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

package main 

import "fmt" 
import "runtime" 

func worker(x_ch <-chan []int, y_ch chan<- []int, wid int) { 

    for x := range x_ch { 
     y := x 
     fmt.Println(" worker", wid, "x:", x) 
     fmt.Println(" worker", wid, "y:", y) 
     y_ch <- y 
    } 
} 

func main() { 

    n_workers := runtime.NumCPU() 
    n_len := 4 
    n_jobs := 4 
    x := make([]int, n_len) 
    x_ch := make(chan []int, 10) 
    y_ch := make(chan []int, 10) 

    for j := 0; j < n_workers; j++ { go worker(x_ch, y_ch, j) } 

    for k := 0; k < n_jobs; k++ { 

//  variant 1: works! 
     x = []int{k, k, k, k} 

//  variant 2: doesn't work! 
//  for i := range x { x[i] = k } 

     fmt.Println("main x:", k, x) 
     x_ch <- x 
    } 

    close(x_ch) 

    for i := 0; i < n_jobs; i++ { 
     z := <- y_ch 
     fmt.Println("  main y:", i, z) 
    } 
} 

Правильный выход (вариант 1):

main x: 0 [0 0 0 0] 
main x: 1 [1 1 1 1] 
main x: 2 [2 2 2 2] 
main x: 3 [3 3 3 3] 
    worker 3 x: [3 3 3 3] 
    worker 3 y: [3 3 3 3] 
    worker 2 x: [2 2 2 2] 
    worker 2 y: [2 2 2 2] 
    worker 1 x: [0 0 0 0] 
    worker 1 y: [0 0 0 0] 
    worker 0 x: [1 1 1 1] 
    worker 0 y: [1 1 1 1] 
     main y: 0 [3 3 3 3] 
     main y: 1 [2 2 2 2] 
     main y: 2 [0 0 0 0] 
     main y: 3 [1 1 1 1] 

Неправильный выход (вариант 2):

main x: 0 [0 0 0 0] 
main x: 1 [1 1 1 1] 
main x: 2 [2 2 2 2] 
main x: 3 [3 3 3 3] 
    worker 3 x: [3 3 3 3] 
    worker 3 y: [3 3 3 3] 
     main y: 0 [3 3 3 3] 
    worker 0 x: [2 2 2 2] 
    worker 0 y: [3 3 3 3] 
     main y: 1 [3 3 3 3] 
    worker 1 x: [1 1 1 1] 
    worker 1 y: [3 3 3 3] 
     main y: 2 [3 3 3 3] 
    worker 2 x: [3 3 3 3] 
    worker 2 y: [3 3 3 3] 
     main y: 3 [3 3 3 3] 

ответ

1

Разница заключается в том, что в варианте 1, вы отправляете другой кусок каждый раз, тогда как в варианте 2 вы отправляете один и тот же срез каждый раз (тот, который создан над петлями for). Не создавая новый срез, вы просто устанавливаете элементы одного и того же среза в разные значения, поэтому goroutines видят, какие значения находятся в срезе, когда они смотрят на него. В варианте 2 main всегда будет видеть [3 3 3 3], потому что это окончательное значение после того, как вы прошли цикл 4 раза. Значение объекта среза содержит ссылку на базовые элементы, а не на сами элементы. Есть хорошее объяснение ломтиков here.

0

Большое спасибо за ваше объяснение, теперь я вижу, где проблема. Я добавил некоторые отладки кода для вывода адреса указателей и результат (со слегка переформатировать выход):

Вариант 1:

main 0 x=[0 0 0 0] &x=0x1830e180 &x[0]=0x1830e1e0 
main 1 x=[1 1 1 1] &x=0x1830e180 &x[0]=0x1830e230 
main 2 x=[2 2 2 2] &x=0x1830e180 &x[0]=0x1830e270 
main 3 x=[3 3 3 3] &x=0x1830e180 &x[0]=0x1830e2a0 
    worker 3 x=[3 3 3 3] &x=0x1830e1d0 &x[0]=0x1830e2a0 
    worker 3 y=[3 3 3 3] &y=0x1830e2e0 &y[0]=0x1830e2a0 
     main 0 y=[3 3 3 3] &y=0x1830e2d0 &y[0]=0x1830e2a0 
    worker 0 x=[0 0 0 0] &x=0x1830e1a0 &x[0]=0x1830e1e0 
    worker 0 y=[0 0 0 0] &y=0x1830e370 &y[0]=0x1830e1e0 
     main 1 y=[0 0 0 0] &y=0x1830e360 &y[0]=0x1830e1e0 
    worker 1 x=[1 1 1 1] &x=0x1830e1b0 &x[0]=0x1830e230 
    worker 1 y=[1 1 1 1] &y=0x1830e400 &y[0]=0x1830e230 
     main 2 y=[1 1 1 1] &y=0x1830e3f0 &y[0]=0x1830e230 
    worker 2 x=[2 2 2 2] &x=0x1830e1c0 &x[0]=0x1830e270 
    worker 2 y=[2 2 2 2] &y=0x1830e480 &y[0]=0x1830e270 
     main 3 y=[2 2 2 2] &y=0x1830e470 &y[0]=0x1830e270 

Вариант 2:

main 0 x=[0 0 0 0] &x=0x1830e180 &x[0]=0x1830e190 
main 1 x=[1 1 1 1] &x=0x1830e180 &x[0]=0x1830e190 
main 2 x=[2 2 2 2] &x=0x1830e180 &x[0]=0x1830e190 
main 3 x=[3 3 3 3] &x=0x1830e180 &x[0]=0x1830e190 
    worker 3 x=[3 3 3 3] &x=0x1830e1d0 &x[0]=0x1830e190 
    worker 3 y=[3 3 3 3] &y=0x1830e2a0 &y[0]=0x1830e190 
     main 0 y=[3 3 3 3] &y=0x1830e290 &y[0]=0x1830e190 
    worker 0 x=[3 3 3 3] &x=0x1830e1a0 &x[0]=0x1830e190 
    worker 0 y=[3 3 3 3] &y=0x1830e330 &y[0]=0x1830e190 
     main 1 y=[3 3 3 3] &y=0x1830e320 &y[0]=0x1830e190 
    worker 1 x=[3 3 3 3] &x=0x1830e1b0 &x[0]=0x1830e190 
    worker 1 y=[3 3 3 3] &y=0x1830e3c0 &y[0]=0x1830e190 
     main 2 y=[3 3 3 3] &y=0x1830e3b0 &y[0]=0x1830e190 
    worker 2 x=[3 3 3 3] &x=0x1830e1c0 &x[0]=0x1830e190 
    worker 2 y=[3 3 3 3] &y=0x1830e440 &y[0]=0x1830e190 
     main 3 y=[3 3 3 3] &y=0x1830e430 &y[0]=0x1830e190 

 Смежные вопросы

  • Нет связанных вопросов^_^