2013-03-23 2 views
6

Играя с каналами и рутингами Go, я столкнулся с своеобразным поведением, которое я надеялся, что кто-нибудь сможет объяснить.Выбор внутри goroutine оценивает каждое другое утверждение

Ниже приведена короткая программа, которая должна печатать пару строк в stdout, отправив строки по каналу в «прослушиватель» (оператор выбора), работающий в отдельной версии goroutine.

package main 

import (
    "fmt" 
    "time" 
) 

func main() { 
    a := make(chan string) 

    go func() { 
     for { 
      select { 
      case <-a: 
       fmt.Print(<-a) 
      } 
     } 
    }() 

    a <- "Hello1\n" 
    a <- "Hello2\n" 
    a <- "Hello3\n" 
    a <- "Hello4\n"   
    time.Sleep(time.Second) 
} 

Использование

go func() { 
    for s := range a { 
     fmt.Print(s) 
    } 
}() 

// or even simpler 

go func() { 
    for { 
     fmt.Print(<-a) 
    } 
}() 

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

Hello2 
Hello4 

т.е. печатается только каждый оператор. Что это за колдовство?

ответ

12

В самом верхнем фрагменте вы извлекаете два значения из канала для каждого цикла. Один в инструкции select и один в заявлении на печать.

Изменить

 select { 
     case <-a: 
      fmt.Print(<-a) 

Для

 select { 
     case val := <-a: 
      fmt.Print(val) 

http://play.golang.org/p/KIADcwkoKs

+0

Спасибо, это имеет смысл. Я отдам это;) – 0sh

7
<-a 

получает значение из канала, деструктивно. Таким образом, в вашем коде вы получаете два значения: одно в выражении select и одно для печати. Тот, который получен в инструкции select, не привязан к какой-либо переменной и поэтому потерян.

Попробуйте

select { 
    case val := <-a: 
     fmt.Print(val) 

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

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