Да, это сложно, но есть несколько правил, которые должны сделать вещи более понятными.
- предпочитает использовать формальные аргументы для каналов вы передаете идти-процедуру вместо доступа к каналам в глобальном масштабе. Вы можете получить больше компилятора, проверяя этот путь, и улучшите модульность.
- избегает как чтения, так и записи на одном канале в конкретной рутинной программе (включая «главный»). В противном случае тупик представляет собой гораздо больший риск.
Вот альтернативная версия вашей программы, применив эти два руководства. Этот случай демонстрирует многие авторам & один читатель на канале:
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()
Это second example включает в себя ожидание наложенного на главной goroutine, которые в противном случае выйти бы быстро и причину остальные пять горитов будут прекращены досрочно (спасибо olov за эту коррекцию).
В обоих примерах не требовалось буферизации. Как правило, хорошим принципом является просмотр буферизации только в качестве усилителя производительности. Если ваша программа не зашла в тупик без буферов, она не будет заторможен с буферами либо (но обратное не всегда верно). Итак, как другое эмпирическое правило, начните без буферизации, затем добавьте его по мере необходимости.
сделать вам не нужно ждать, пока все goroutines закончить? – mlbright
Это зависит от того, что вы имеете в виду. Взгляните на примеры play.golang.org; у них есть функция «main», которая заканчивается, как только она достигает конца, независимо от того, что делают другие goroutines. В первом примере выше 'main' является блокировкой с другими goroutines, поэтому нет проблем.Второй пример также работает без проблем, потому что все сообщения отправляются через 'c' * перед тем, как вызывается функция' close', и это происходит * до того, как закончится 'main' goroutine. (Вы можете утверждать, что вызов 'close' является излишним в этом случае, но это хорошая практика.) –
, предполагая, что вы хотите (детерминистически) видеть 15 распечаток в последнем примере, вам нужно подождать. Чтобы продемонстрировать это, вот тот же пример, но со временем. Слез прямо перед Printf: http://play.golang.org/p/cEP-UBPLv6 – olov