Проверьте, читал ли кто-то с канала Go - PullRequest
0 голосов
/ 12 апреля 2019

Как мы можем установить что-то вроде прослушивателя на ходовых каналах, чтобы, когда кто-то читал что-то с канала, которые уведомляли нас?

Представьте, что у нас есть sequence number для записей в канале, и мы хотим уменьшить его, когда кто-топрочитал значение из нашего канала где-то вне нашего пакета.

Ответы [ 3 ]

1 голос
/ 12 апреля 2019

Небуферизованные каналы передают данные синхронно, так что вы уже знаете, когда данные читаются. Буферизованные каналы работают аналогично, когда буфер заполнен, но в противном случае они не блокируют то же самое, поэтому такой подход не скажет вам совершенно то же самое. В зависимости от ваших потребностей, рассмотрите возможность использования таких инструментов, как sync.WaitGroup .

ch = make(chan Data)
  ⋮
for {
      ⋮
    // make data available
    ch <- data

    // now you know it was read
    sequenceNumber--
      ⋮
}
1 голос
/ 12 апреля 2019

Вы можете создать механизм ретрансляции каналов для захвата событий чтения в реальном времени.

Так, например:

func relayer(in <-chan MyStruct) <-chan MyStruct {
        out := make(chan MyStruct) // non-buffered chan (see below)

        go func() {     
                defer close(out)
                readCountLimit := 10

                for item := range in {
                        out <- item
                        // ^^^^ so this will block until some worker has read from 'out'
                        readCountLimit--
                }
        }()     
        return out      
}

Использование:

type MyStruct struct {
        // put your data fields here
}

ch := make(chan MyStruct) // <- original channel - used by producer to write to

rch := relayer(ch) // <- relay channel - used to read from

// consumers
go worker("worker 1", rch)
go worker("worker 2", rch)

// producer
for { ch <- MyStruct{} }
0 голосов
/ 12 апреля 2019

Вы можете сделать это в ручном режиме. внедрить какой-то маркер ACK в сообщение. Как то так:

type Msg struct {
    Data int
    ack  bool
}

func (m *Msg) Ack() {
    m.ack = true
}

func (m *Msg) Acked() bool {
    return m.ack
}

func main() {
    ch := make(chan *Msg)
    msg := &Msg{Data: 1}
    go func() {
        for {
            if msg.Acked() {
                // do smth
            }
            time.Sleep(10 * time.Second)
        }
    }()
    ch <- msg

    for msg := range ch {
        msg.Ack()
    }
}

Код не проверен. Вы также можете добавить некоторую дополнительную информацию в метод Ack(), скажем, метаинформацию о package и func, откуда был вызван Ack(), этот ответ может быть связан: https://stackoverflow.com/a/35213181/3782382

...