Построение асинхронной архитектуры с каналом для чтения элементов и каналом завершения
столкнулся с такой ситуацией, что не уверен, как поведет себя в 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 шт):
В вашей ситуации не нужно создавать второй канал. Когда запишите всё в канал, его нужно просто закрыть.
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
}
}