Перейти каналы без буферизации

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 отправить ".

Другие вопросы по тегам