golang case, вызываемое другим case, не выполняется, но возвращает - PullRequest
0 голосов
/ 01 февраля 2020

Почему Stopped не распечатывается, а вместо этого возвращает main?

package main

import (
    "fmt"
    "time"
)

func main() {
    tick := time.Tick(100 * time.Millisecond)
    boom := time.After(500 * time.Millisecond)
    var stop chan int = make(chan int)
    for {
        select {
        case <- stop:
            fmt.Println("Stopped!")
        case <-tick:
            fmt.Println("tick.")
        case <-boom:
            fmt.Println("BOOM!")
            stop <- 0
        default:
            fmt.Println("    .")
            time.Sleep(50 * time.Millisecond)
        }
    }
}

Вывод:

   .
    .
tick.
    .
    .
tick.
    .
    .
tick.
    .
    .
tick.
    .
    .
tick.
BOOM!

Ожидаемое:

   .
    .
tick.
    .
    .
tick.
    .
    .
tick.
    .
    .
tick.
    .
    .
tick.
BOOM!
Stopped!

Ответы [ 3 ]

5 голосов
/ 01 февраля 2020

В спецификации языка программирования Go сказано следующее об отправке на канал:

Коммуникационные блоки, пока отправка не может быть продолжена. Отправка по небуферизованному каналу может продолжаться, если получатель готов. Отправка по буферизованному каналу может продолжаться, если в буфере есть место.

Так что, когда ваш код достигает значения stop <- 0, он блокирует ожидание другой программы для чтения из канала, и это никогда не происходит ( ваш case <- stop: находится в пределах той же самой подпрограммы go, поэтому он не активен).

Существует несколько способов решения этой проблемы:

  1. Использование буферизованного канала (например, stop := make(chan int, 1)).
  2. Ожидание остановки в другой подпрограмме go ( пример )
  3. Закрыть канал вместо отправки чего-либо на него (close(stop)).

Примечание: из-за того, как написано ваше приложение, ни один из этих вариантов не остановит его, потому что ваш для l oop никогда не завершается (добавьте break или return для выхода).

3 голосов
/ 01 февраля 2020

Когда происходит BOOM, основная программа stsrts ожидает записи, чтобы остановить канал. Но нет других подпрограмм, ожидающих чтения из него, так что это тупик.

Если вы сделаете остановочный канал буферизованным каналом с пропускной способностью 1, тогда он сможет записывать в него, и следующая итерация будет читать. Или просто закройте канал.

0 голосов
/ 01 февраля 2020

@ Джибуриру это работает.

package main

import (
    "fmt"
    "time"
)

func main() {
    tick := time.Tick(100 * time.Millisecond)
    boom := time.After(500 * time.Millisecond)
    stop := make(chan int)
    for {
        select {
        case <-stop:
            fmt.Println("Stopped!")
            return
        case <-tick:
            fmt.Println("tick.")
        case <-boom:
            fmt.Println("BOOM!")
            close(stop)
        default:
            fmt.Println("    .")
            time.Sleep(50 * time.Millisecond)
        }
    }
}

Вывод следует.

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