Построение асинхронной архитектуры с каналом для чтения элементов и каналом завершения

столкнулся с такой ситуацией, что не уверен, как поведет себя в golang при последовательном считывании из канала, которое должно завершиться done сигналом из "выходного канала". Вот пример, который характеризует мой код:

func f() {
    doneCh := make(chan struct{})
    trafficCh := make(chan interface{})

    go write(doneCh, trafficCh)
    read(doneCh, trafficCh)
}


func write(doneCh chan<- struct{}, sendCh chan<- interface{}) {
    defer func() {
        doneCh <- struct{}{}
    }()

    for {
        // Send something in sendCh
    }
}


func read(doneCh <-chan struct{}, recvCh <-chan interface{}) {
    for {
        select {
            case <-doneCh:
                return
            case item := <-recvCh:
                // Something do with item
        }
    }
}

По стандарту, если у select пришло несколько сообщений в разные каналы, то он выбирает случайный. Возможна ли такая ситуация, что, когда select будет выбирать канал, то он увидит сообщение и в doneCh и recvCh, т.е. возникнет неопределённое поведение, и мы можем завершить чтение, не считав все элементы.


Ответы (1 шт):

Автор решения: Nik

В вашей ситуации не нужно создавать второй канал. Когда запишите всё в канал, его нужно просто закрыть.

func f() {
    trafficCh := make(chan string)

    go write(trafficCh)
    read(trafficCh)
}

func write(sendCh chan<- string) {
    // Записать всё что нужно
    for i := 0; i < 100; i++ {
        sendCh <- fmt.Sprintf("HELLO %d", i)
    }
    close(sendCh)
}

func read(recvCh <-chan string) {
    for str := range recvCh {
        fmt.Println(str)
    }
}

На будущее... Часто приходится выделить приоритет из каналов, какой из них должен быть прочитан первым. Для этого делают так: (на первый взгляд выглядит странно)

for {
        select {
        case item := <-recvCh:
            // Something do with item
        default:
        }
        select {
        case <-doneCh:
            return
        case item := <-recvCh:
             // Something do with item
        }
    }
→ Ссылка