#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.