关于select非阻塞通道操作的问题

问题1:

messages := make(chan string)
signals := make(chan bool)

select {
case msg := <-messages:
    fmt.Println("received message", msg)
default:
    fmt.Println("no message received")
}

msg := "hi"
select {
case messages <- msg:
    fmt.Println("sent message", msg)
default:
    fmt.Println("no message sent")
}

select {
case msg := <-messages:
    fmt.Println("received message", msg)
case sig := <-signals:
    fmt.Println("received signal", sig)
default:
    fmt.Println("no activity")
}

不是应该输出:

no message received
sent messagehi
received messagehi

怎么会是:

no message received
no message sent
no activity

问题2:

ch := make(chan int, 1)

for {
    select {
    case ch <- 0:
    case ch <- 1:
    }
    i := <-ch
    fmt.Println("value=", i)
}

程序怎么会交替随机输出0和1呢?

共 3 个回复


chenhao

问题2找到答案了,golang的select机制问题,详见https://golang.org/ref/spec#Select_statements

# 0

chenhao

问题1还是不明白,第一个select( case msg := <-messages)不是为第二个select提供接收者了吗,怎么还是输出"no message sent"

# 1

David

第一个 select 里面的 case msg := <-messages 虽然尝试执行,但是由于当时 messages 里面没有数据,所以最后执行的是 default,所以 <- 操作就没有执行,messages 又没有 buffer,所以第二个 select 执行的时候已经没有 goroutine 在接受 messages 里面的数据了,自然没法 send 数据。

第一个 select 可以来理解为:

if messages has data to be read {
    msg := <- messages
    // execute code after the case statement
} else {
    // default
}

当然,上面的代码第一行和第二行是原子的执行的。如果messages当时没有数据,又可以不 block,那么就相当于messages什么也没变化。

# 2