Вы используете небуферизованные каналы, которые работают как точка синхронизации между основной и второй программами.
В этом случае вы знаете только, что, когда вторая процедура находится здесь messages <- "ping1"
, главная находится в строке for msg := range messages
. Таким образом, нет гарантии, что основной цикл достигнет println(msg)
немедленно. То есть, в то же время вторая программа могла продвинуться и достичь линий println("p2")
и messages <- "ping2"
.
Как контрпример, я добавляю канал только для обеспечения полной синхронизации между отпечатками.
package main
func rtn(messages chan<- string, syncChan chan struct{}) {
defer close(messages)
println("p1")
messages <- "ping1"
//Wait for main goroutine to print its message
<-syncChan
//for i := 0; i < 10000000; i++ { }
println("p2")
messages <- "ping2"
//Wait for main goroutine to print its message
<-syncChan
}
func main() {
messages := make(chan string)
syncChan := make(chan struct{})
go rtn(messages, syncChan)
for msg := range messages {
println(msg)
//Notify the second goroutine that is free to go
syncChan <- struct{}{}
}
}
Который печатает результат, который вы ожидали:
p1
ping1
p2
ping2
Вот еще один пример, который выдает результат, который вы ищете. В этом случае основная программа была принудительно заблокирована time.Sleep()
. Это сделает вторую процедуру готовой к отправке до того, как получатель будет готов принять. Следовательно, отправитель фактически заблокирует операцию отправки.
package main
import (
"time"
)
func rtn(messages chan<- string) {
defer close(messages)
println("p1")
messages <- "ping1"
//for i := 0; i < 10000000; i++ { }
println("p2")
messages <- "ping2"
}
func main() {
messages := make(chan string)
go rtn(messages)
//Put main goroutine to sleep. This will make the
//sender goroutine ready before the receiver.
//Therefore it will have to actually block!
time.Sleep(time.Millisecond * 500)
for msg := range messages {
println(msg)
}
}