Почему следующая операция канала заблокирована? т.е. вниз по течению <- <- вверх по течению - PullRequest
1 голос
/ 06 марта 2020

У меня есть два канала, восходящий и нисходящий. Моя цель - прочитать данные из восходящего потока и передать их в нижестоящий поток. Однако, когда контекст отменен, я хотел бы выйти изящно без тупика.

Я пытался быть "умным" и сделал что-то вроде следующего.

func main() {
    upstream := make(chan struct{})
    ctx, cancel := context.WithCancel(context.Background())
    go func() {
        <-time.After(5 * time.Second)
        cancel()
    }()

    // Buffered downstream ensures no blocking in this scenario
    downstream := make(chan struct{}, 1)
    select {
    case <-ctx.Done():
        log.Println("context is killed")
    case downstream <- <-upstream:
        log.Println("transferred value from upstream to downstream")
    }
}

Тогда я зашел в тупик. Однако, если я перестану быть ленивым и сделаю следующее,

func main() {
    upstream := make(chan struct{})
    ctx, cancel := context.WithCancel(context.Background())
    go func() {
        <-time.After(5 * time.Second)
        cancel()
    }()

    // Buffered downstream ensures no blocking in this scenario
    downstream := make(chan struct{}, 1)
    select {
    case <-ctx.Done():
        log.Println("context is killed")
    case val := <-upstream:
        downstream <-val
        log.Println("transferred value from upstream to downstream")
    }
}

Она вышла прекрасно, без тупика. Подскажите, пожалуйста, в чем ключевое отличие между

downstream <- <-upstream

и

val := <-upstream
downstream <-val

1 Ответ

1 голос
/ 06 марта 2020

Оператор выбора не работает с оператором получения <-upstream, он работает с оператором отправки downstream <-.

Прежде чем дело выбора сможет определить, готов ли оператор отправки downstream <-, сначала он должен оценить выражение аргумента, которое равно <-upstream. Поскольку ничего не отправляется на upstream, эта оценка блокируется. Это означает, что вы вообще никогда не попадете в выбранные варианты.

Эквивалентный многострочный код будет выглядеть следующим образом, поэтому становится совершенно очевидно, почему он не работает.

val := <-upstream
select {
case <-ctx.Done():
    log.Println("context is killed")
case downstream <- val:
    log.Println("transferred value from upstream to downstream")
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...