Подтвердить что ты не робот

Golang - Как узнать, что буферный канал заполнен

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

4b9b3361

Ответ 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