Выберите заблокированный вызов и канал

#go #concurrency #channel

#Вперед #параллелизм #канал

Вопрос:

Я почти уверен, что раньше видел вопрос по этому вопросу, но сейчас не могу его найти.

По сути, я хочу select использовать заблокированный вызов, а также канал.

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

Есть ли идиоматический способ написать это, которого мне не хватает?

Оптимально было бы что-то вроде:

 select {
case a <- c:
  ...
case ans := connection.Read():
  ...
}
  

Комментарии:

1. Ваше «предлагаемое» решение будет ожидать заблокированного вызова ИЛИ канала, в зависимости от того, что произойдет раньше. Согласно тексту вашего вопроса, вы хотите дождаться заблокированного вызова И канала (дождитесь завершения обоих). Что вы хотите?

2. @icza да, извините, имел в виду или 🙂

Ответ №1:

Если у вас есть канал и функция, которую вы хотите использовать select , использование подпрограммы и канала является идиоматическим решением. Обратите внимание, однако, что если значение будет получено из канала, это не повлияет на функцию, и она продолжит выполняться. Вы можете использовать context.Context , чтобы сообщить, что его результат больше не нужен, и он может завершиться досрочно.

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

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

Обратите внимание, что если вам нужно сделать это во многих местах, вы можете создать вспомогательную функцию, чтобы запускать ее асинхронно:

 func launch(f func()) <-chan struct{} {
    done := make(chan struct{})
    go func() {
        defer close(done)
        f()
    }()
    return done
}
  

Пример функции:

 func test() {
    time.Sleep(time.Second)
}
  

А затем, используя его:

 select {
case a := <-c:
    fmt.Println("received from channel:", a)
case <-launch(test):
    fmt.Println("test() finished")

}
  

Попробуйте это на игровой площадке Go.