Как узнать, что буферный канал заполнен? Я не знаю, чтобы быть заблокированным, когда буферный канал заполнен, вместо этого я хочу отказаться от отправленного элемента в буферный канал.
Golang - Как узнать, что буферный канал заполнен
Ответ 1
Вы можете использовать оператор select
по умолчанию. В случае, если невозможно выполнить какой-либо из таких случаев, например, отправить на полный канал, инструкция будет выполнять по умолчанию:
package main
import "fmt"
func main() {
ch := make(chan int, 1)
// Fill it up
ch <- 1
select {
case ch <- 2: // Put 2 in the channel unless it is full
default:
fmt.Println("Channel full. Discarding value")
}
}
Вывод:
Канал заполнен. Отбрасывание значения
Игровая площадка: http://play.golang.org/p/1QOLbj2Kz2
Проверить без отправки
Также можно проверить количество элементов, помещенных в очередь в канале, используя len(ch)
, как указано в Go спецификации.
Это в сочетании с cap
позволяет нам проверить, заполнен ли канал, не отправляя никаких данных.
if len(ch) == cap(ch) {
// Channel was full, but might not be by now
} else {
// Channel wasn't full, but might be by now
}
Обратите внимание, что результат сравнения может быть недействительным к моменту ввода блока if
Ответ 2
вместо этого я хочу удалить элемент, отправленный в буферный канал.
Это называется "переполняющим каналом", и вы найдете ответ ANisus, реализованный в eapache/channels/overflowing_channel.go
:
for elem := range ch.input {
// if we can't write it immediately, drop it and move on
select {
case ch.output <- elem:
default:
}
}
close(ch.output)
Но этот проект eapache/channels реализует другие стратегии:
-
OverflowingChannel
реализует интерфейсChannel
таким образом, который никогда не блокирует автора.
В частности, если значение записывается вOverflowingChannel
, когда его буфер заполнен (или в небуферизованном случае, когда получатель не готов), то это значение просто отбрасывается.
Для противоположного поведения (отбрасывание самого старого элемента, а не самого нового) см.
RingChannel
.
Ответ 3
Другим полезным примером, на который я наткнулся, был эта отличная реализация Ring Buffer.
Цитата из источника:
Идея проста: подключите два буферизованных канала через один Горутин, который пересылает сообщения с входящего канала на исходящий канал. Всякий раз, когда новое сообщение не может быть помещено на исходящий канал, выведите одно сообщение из исходящего канала (это является самым старым сообщением в буфере), отбросьте его и поместите новый сообщение в недавно освобожденном исходящем канале.
Отметьте эту версию C...
Ответ 4
Используйте len(channel)
, чтобы проверить, сколько элементов в данный момент находится в канале, и сравните его с cap(channel)
, его емкость:
func TestChannelFull(t *testing.T) {
chansize := 100
ch := make(chan bool, chansize)
t.Log(cap(ch))
t.Log(len(ch))
for len(ch) < cap(ch) {
ch <- true
}
t.Log(len(ch))
t.Log("quit because channel is full")
}
init_test.go:25: 100
init_test.go:26: 0
init_test.go:30: 100
init_test.go:31: quit because channel is full
PASS