Почему запись канала заблокирована несмотря на то, что горутин выбирает на этом канале? - PullRequest
1 голос
/ 22 мая 2019

Меня смущает следующий код, я записываю некоторые комментарии в коде, которые указывают на мою путаницу. И есть результат выполнения в конце кода, я также записываю ожидаемый результат.

package main

import (
    "fmt"
    "time"
)

func sendRPC() bool {
    time.Sleep(5 * time.Second)
    return true
}

func main() {
    done := make(chan struct{})
    ch := make(chan bool)

    go func() { // goroutine A
        select {
        case ch <- sendRPC():
            fmt.Println("RPC return")
        case <-done:
            fmt.Println("exit")
        }
    }()

    select {
    case <-ch:
    case <-time.After(1000 * time.Millisecond):
        fmt.Println("timeout")
        if len(done) == 0 {
            fmt.Println("1")
            // here write done channel will block until sendRPC() return, why?
            // I expect that the write is nonblock because goroutine A is select on done channel.
            done <- struct{}{}
            fmt.Println("2")
        }
    }

    // result:
    // timeout (after about 1 second)
    // 1
    // exit    (after about 5 seconds, I expect that it is printed after about 1 second too.)
    // 2

}

1 Ответ

1 голос
/ 22 мая 2019

Спецификация гласит: :

Для всех случаев в операторе операнды канала операций приема и выражения канала и выражения правой части операторов отправкивычисляется ровно один раз, в исходном порядке, после ввода оператора "select".Результатом является набор каналов для приема или отправки и соответствующие значения для отправки.Любые побочные эффекты в этой оценке будут иметь место независимо от того, какая (если таковая имеется) операция связи выбрана для продолжения.

Набор каналов для выбора в программе A ожидает оценки sendRPC().Это может помочь взглянуть на эту эквивалентную программу:

go func() { // goroutine A
    v := sendRPC()  // waits for 5 seconds
    select {
    case ch <- v:
        fmt.Println("RPC return")
    case <-done:
        fmt.Println("exit")
    }
}()

Прием на done задерживается на 5 секунд.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...