Да, это сложно, но есть пара практических правил, которые должны сделать все намного проще.
- предпочитают использовать формальные аргументы для каналов, которые вы передаете подпрограммам, вместо доступа к каналам в глобальной области. Таким образом вы можете получить больше проверок компилятора, а также лучшую модульность.
- Избегайте чтения и записи на одном и том же канале в конкретном рутине (включая «основной»). В противном случае тупиковая ситуация представляет собой гораздо больший риск.
Вот альтернативная версия вашей программы, в которой применяются эти два правила. Этот случай демонстрирует, как много писателей и один читатель на канале:
c := make(chan string)
for i := 1; i <= 5; i++ {
go func(i int, co chan<- string) {
for j := 1; j <= 5; j++ {
co <- fmt.Sprintf("hi from %d.%d", i, j)
}
}(i, c)
}
for i := 1; i <= 25; i++ {
fmt.Println(<-c)
}
http://play.golang.org/p/quQn7xePLw
Он создает пять программ записи в один канал, каждая из которых записывает пять раз. Основная процедура чтения читает все двадцать пять сообщений - вы можете заметить, что порядок, в котором они появляются, часто не является последовательным (т. Е. Очевиден параллелизм).
Этот пример демонстрирует особенность каналов Go: можно иметь несколько писателей, совместно использующих один канал; Go автоматически чередует сообщения.
То же самое относится к одному писателю и нескольким читателям на одном канале, как показано во втором примере здесь:
c := make(chan int)
var w sync.WaitGroup
w.Add(5)
for i := 1; i <= 5; i++ {
go func(i int, ci <-chan int) {
j := 1
for v := range ci {
time.Sleep(time.Millisecond)
fmt.Printf("%d.%d got %d\n", i, j, v)
j += 1
}
w.Done()
}(i, c)
}
for i := 1; i <= 25; i++ {
c <- i
}
close(c)
w.Wait()
Этот второй пример включает ожидание, наложенное на основную горутину, которая в противном случае немедленно завершилась бы и вызвала бы досрочное завершение остальных пяти горутин (спасибо olov за это исправление) .
В обоих примерах буферизация не требовалась. Обычно полезно рассматривать буферизацию только как средство повышения производительности. Если ваша программа не блокируется без буферов, она не будет блокироваться и с буферами (но обратное не всегда верно). Итак, как еще одно практическое правило, начните без буферизации, а затем добавляйте ее позже по мере необходимости .
original, hi from 4
...