Перейти каналы без буферизации
package main
import (
"fmt"
"time"
)
var message chan string
func main() {
message = make(chan string)
count := 6
flag := "first"
go func() {
fmt.Println("child go ",flag)
for i := 0; i < count; i++ {
fmt.Println("set:",i)
message <- fmt.Sprintf("message %d",i)
}
}()
time.Sleep(time.Second * 0)
fmt.Println("main thread ",flag)
flag = "last"
for i := 0 ; i < count; i++ {
fmt.Println("get:",i)
fmt.Println(<-message)
}
}
Я запускаю код и результат:
main thread first
get: 0
child go last
set: 0
set: 1
message 0
get: 1
message 1
get: 2
set: 2
set: 3
message 2
get: 3
message 3
get: 4
set: 4
set: 5
message 4
get: 5
message 5
Я смущен результатом. Почему "сообщение 1" появляется после "получить 1", а не "установить 2"? Это озадачило меня на несколько дней!
Я думаю, что когда он получает "get 1", основная процедура go должна быть заблокирована, а дочерняя процедура go должна быть exec'd, отправлять "message 1" на канал сообщения и продолжать цикл for и печатать "set 2", таким образом блокируясь на отправьте "сообщение 2" на канал, так что основной запуск программы запускается, выведите "сообщение 1".
1 ответ
Код делает именно то, что вы думаете, он должен делать (если я понимаю, что вы думаете, что он должен делать): получение от message
блоки, пока значение не было отправлено. К сожалению, ваш код печатает "set 2" перед отправкой на канал, и эта операция не заблокирована.
Синхронизация происходит только при <-
, Println до отправки канала может работать. Взгляните на http://play.golang.org/p/d6_SkBugqs который печатает до и после каждой операции отправки / получения, и вы увидите, что все правильно сопоставлено: все "post-recv n" происходят после "pre отправить ".