Чтобы ответить на основные вопросы:
- Это нормально, чтобы покинуть канал, это будет мусор.
- Это кажется основанным на мнении, но для меня, если толькопричина, по которой вы создаете буферизованный канал с 10 пробелами, заключается в том, что программы-отправители могут выйти;Такое ощущение, что это выиграет от редизайна.Существуют и другие (возможно, более эффективные) способы обеспечения того, чтобы программы-отправители могли закрываться.
По сути, вы создаете неявную связь между количеством рабочих и размером буферизованного канала.Измените одно из этих двух чисел, и что-то зафиксируется / сломается!(В качестве примечания, буферизованные каналы обычно используются в тех случаях, когда потребитель и производители работают с одинаковой скоростью, но у одного нет стабильного выхода. Он колючий, буфер сглаживает пики и впадины.)
Имея это в виду, я рекомендую, чтобы было явным по поводу управления тем фактом, что вам не нужны все значения.
Вот обновленная версия getRandomInt () функция.Обратите внимание на настройку отмены контекста с помощью defer вверху и использование оператора select при отправке.
func getRandomInt() (int, error) {
ctx := context.Background() // creates a fresh, empty context
ctx, cancel := context.WithCancel(ctx)
defer cancel() // cancels the context when getRandomInt() returns
ch := make(chan int)
// 10 senders
for i := 0; i < 10; i++ {
go func(i int) {
defer fmt.Printf("Goroutine #%d finished\n", i)
fmt.Printf("Goroutine #%d started\n", i)
data := heavyJob()
// this select statement wil block until either this goroutine
// is the first to send, or the context is cancelled. In which case
// another routine has already sent and it can discard it's values.
select {
case ch <- data:
fmt.Printf("Goroutine #%d sent data %d to ch\n", i, data)
case <-ctx.Done():
fmt.Printf("Goroutine #%d did not send, context is cancelled, would have sent data %d to ch\n", i, data)
}
}(i)
}
// 1 receiver
timeout := time.After(2000 * time.Millisecond)
select {
case value := <-ch:
// uses only the value received first, the rest are discarded
return value, nil
case <-timeout:
return -1, errors.New("Timeout")
}
}
Настройка контекста с отменой означает, что контекст становится «Готово» после cancel()
функция вызывается.Это способ сказать всем подпрограммам отправителя не беспокоиться об ожидании отправки.
При отправке оператор выбора блокируется до тех пор, пока какой-либо контекст не будет отменен функцией cancel()
;или метод получателя читает первое значение.
Я также удалил буферизацию из канала, так как больше в этом нет необходимости.