2015-04-14 3 views
1

попытался запустить следующий код (производитель & потребителя), чтобы понять goroutines и канал в golang (удалить пакет и импорт из кода ниже):производителя потребитель golang

var done = make(chan bool) 
var msgs = make(chan int) 

func produce() { 
    for i := 0; i < 10; i++ { 
      msgs <- i 
    } 
    fmt.Println("Before closing channel") 
    close(msgs) 
    fmt.Println("Before passing true to done") 
    done <- true 
} 

func consume() { 
    for { 
      msg := <-msgs 
      time.Sleep(100 * time.Millisecond) 
      fmt.Println("Consumer: ", msg) 
    } 
} 

func main() { 
    go produce() 
    go consume() 
    <-done 
    fmt.Println("After calling DONE") 
} 

исходного код из: http://www.golangpatterns.info/concurrency/producer-consumer

Ниже выводится при запуске кода

Consumer: 0 
Consumer: 1 
Consumer: 2 
Consumer: 3 
Consumer: 4 
Consumer: 5 
Consumer: 6 
Consumer: 7 
Consumer: 8 
Before closing channel 
Before passing true to done 
After calling DONE 

Основываясь на моем понимании с goroutines и каналом: Когда мы вызываем функцию produ() и потребляем() из main() с использованием ключевого слова go, переходим к runtime kicks из 2 goroutines (вроде потоков в java-мире, но не в реальных потоках ОС), а главный() goroutine приходит и останавливается на " < -done ". Теперь внутри production() - цикл идет от 0 до 9, а внутри цикла канал msgs получает int (от 0 до 9) 1 за время, которое потребляется параллельно потреблением(); однако продукция не имеет понятия об этом, и она просто держит зацикливание от 0 до 9.

Вопрос: Предполагая, что мое понимание правильное. Однажды цикл for сделан, почему следующая printLine внутри продукта() не печатается, а также почему канал msgs не закрывается? Почему goroutine останавливается внутри продукта(), пока потребитель не потребляет все msgs?

+0

Операторы печати в производителе получить печатный и канал msgs закрывается сразу после выхода цикла for. Я не понимаю, о чем вы спрашиваете. – JimB

+0

Тогда почему на выходе выводятся инструкции печати - «Перед закрытием канала» и «Перед передачей правдоподобного результата» после «Потребитель: 8», т. Е. После того, как все msgs будут использованы? – srock

+1

Отправка и получение по небуферизованному каналу синхронно. Документы, вероятно, помогут: http://golang.org/doc/effective_go.html#channels – JimB

ответ

1

Канал msgs небуферизован. Это означает, что для отправки для завершения должна быть выполнена соответствующая операция приема, которая также может быть завершена. Это обеспечивает точку синхронизации между goroutines.

Это легко увидеть, если вы просто добавить несколько более оператор печати на ваш пример

http://play.golang.org/p/diYQGN-iwE

func produce() { 
    for i := 0; i < 4; i++ { 
     fmt.Println("sending") 
     msgs <- i 
     fmt.Println("sent") 
    } 
    fmt.Println("Before closing channel") 
    close(msgs) 
    fmt.Println("Before passing true to done") 
    done <- true 
} 

func consume() { 
    for msg := range msgs { 
     fmt.Println("Consumer: ", msg) 
     time.Sleep(100 * time.Millisecond) 

    } 
} 

Выход:

sending 
Consumer: 0 
sent 
sending 
Consumer: 1 
sent 
sending 
Consumer: 2 
sent 
sending 
Consumer: 3 
sent 
Before closing channel 
Before passing true to done 
After calling DONE 
+0

Вы также можете увидеть это, отредактировав оригинал, чтобы иметь что-то вроде 'var msgs = make (chan int, 99)'; буферизованный канал с более чем достаточным количеством места. В этом случае главный, скорее всего, выйдет до того, как потребитель сможет потреблять что угодно/все (точный порядок не определен). –

+0

Идея теперь имеет смысл. Спасибо за подробное объяснение, @JimB. – srock

+0

Я устал делать канал msgs как буферизированный. Добавлены несколько операторов печати внутри consume(). Я видел, что каждый раз, когда я запускал код, «fmt.Println (« После вызова DONE ») был напечатан, и даже после этого я мог видеть, как распечатывают заявления изнутри функции потребления(), печатаемой. Неправильно ли, что всякий раз, когда «<-done» получает сообщение в этом случае bool, он не дожидается завершения какого-либо goroutine? Итак, почему в этом случае, даже если <-done был получен, и «После вызова DONE» был напечатан, я все еще вижу, что continue() goroutine продолжается? – srock

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