Почему мой оператор for for select продолжает получать с моего канала даже после его закрытия? - PullRequest
0 голосов
/ 10 октября 2019

У меня есть следующий код:

package main

import (
    "fmt"
    "time"
)

func main() {
    ch := make(chan int)
    ch2 := make(chan int)
    go func(c chan int, c2 chan int) {
        for {
            select {
            case v := <-c:
                fmt.Println(v)
            case v := <-c2:
                fmt.Println(v)
            default:
            }
        }
    }(ch, ch2)
    ch <- 1
    close(ch)
    close(ch2)
    time.Sleep(10 * time.Second)
}

Когда я запускаю это, он печатает 1 на стандартный вывод, а затем продолжает печатать 0. Почему это так?

Я знаю, что могу проверить, закрыт ли канал в моей процедуре, но я просто хочу узнать причину этого.

Кроме того, предположим, что я хочу выйти изПосле того, как все (несколько) каналов закрыты, это возможно? Я предполагал, что, как только все каналы будут закрыты, я могу потенциально выйти из программы в случае по умолчанию после закрытия всех каналов

Ответы [ 2 ]

5 голосов
/ 10 октября 2019

Это ожидаемое поведение для Спецификация: Оператор получения:

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

См. Как ведет себя неинициализированный канал?

Если вы хотитечтобы завершить цикл, как только все значения были получены от канала (которые были отправлены на него до его закрытия), используйте конструкцию for ... range, например:

c := make(chan int) // Initialize some channel

for v := range c {
    fmt.Println("Received:", v)
}

Если у вас есть несколько каналов ивы хотите получать от всех, вы можете использовать несколько процедур, каждая из которых имеет for range для назначенного канала.

Другое решение:

Функция может читать с нескольких входови продолжайте, пока все не закроются, путем мультиплексирования входных каналов на один канал, который закрыт, когда все входы закрыты. Это называется фан-ин.

Подробнее об этом читайте в Шаблоны Go Go Concurrency: конвейеры и отмена: Fan-out-fain-in .

3 голосов
/ 10 октября 2019

Спецификация языка программирования Go n

Закрыть

После вызова close и после получения любых ранее отправленных значенийОперации приема возвращают нулевое значение для типа канала без блокировки.

Оператор приема

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

...