2015-10-08 2 views
0

У меня есть файл:goroutine проходит только половину значений через канал

package main 
import "fmt" 

func 
combinations(result chan []byte, len int, min byte, max byte) { 
    res := make([]byte,len) 
    for i := 0; i < len; i++ { 
     res[i] = min 
    } 
    result <- res 
    for true { 
     i := 0 
     for i = 0; i < len; i++ { 
      if res[i] < max { 
       res[i] = res[i] + 1; 
       break 
      } else { 
       res[i] = 32 
      } 
     } 
     result <- res 
     if(i == len) { 
      close(result) 
      return; 
     } 
    } 
} 

func 
main() { 
    combination_chan := make(chan []byte) 
    go combinations(combination_chan, 2, 0, 5) 
    for next_combination := range combination_chan { 
     fmt.Printf("%x\n",next_combination) 
    } 
} 

Я ожидаю, что это напечатать все возможные комбинации 2 байта в диапазоне от 0 до 5, IE:

0000 
0100 
... 
0001 
... 
0505 

Однако, это, кажется, пропустить все другое значение, и печатать то же значение дважды, IE:

0100 
0100 
0300 
0300 
... 

Почему бы это делать это? Я вставил отпечатки перед «результатом < - res», и все это правильно.

ответ

2

Если мы немного упростим, фрагмент в Go в основном является указателем на массив, поэтому, передав срез, который вы все еще являетесь владельцем и изменяете через канал, вы создаете гонку данных.

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

Таким образом, весь ваш алгоритм приводит к неопределенному поведению, потому что вы повторяете одно и то же содержимое снова и снова при их изменении.

Решение в вашем случае будет скопировать кусочек перед отправкой его через канал:

buf := make([]byte, len(res)) 
copy(buf, res) 
result <- buf 

Смотреть это работает здесь: http://play.golang.org/p/ulLYy9Uqnp

Кроме того, я не рекомендую использовать len как имя переменной, поскольку оно может конфликтовать с встроенной функцией len().

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