有没有办法更新已发送到具有更新数据的频道的未读数据?
我有一个goroutine(制作人),其频道为另一个goroutine(消费者)提供进度更新。在某些情况下,进度可以比消费者使用更新消息更快地更新。
这使我遇到问题:
举个例子,我可能会有这样的事情:
Progress reporting goroutine: Posts "1%" to channel
Progress reporting goroutine: Posts "2%" to channel
Progress reporting goroutine: Posts "3%" to channel
Progress consuming goroutine: Reads "1%", "2%" and "3%" from channel. "1% and "2%" are outdated information.
有没有办法更新未读的频道数据?或者有更好的方法来解决这个问题吗?
答案 0 :(得分:2)
您可以将某些值存储在受RWMutex
保护的全局变量中。它会保持进度。发电机更新它。消费者阅读和节目。
此外,您可以对长度为1的通道进行非阻塞写入:
var c = make(chan struct{}, 1)
select {
case c <- struct{}{}:
default:
}
这种方式发送者要么在通道中添加一个元素,要么在它已满时不执行任何操作。
Reader将这个空结构视为一个信号 - 它应该采用全局变量中的更新值。
另一种方式:可更新频道
var c = make(chan int, 1)
select {
case c <- value: // channel was empty - ok
default: // channel if full - we have to delete a value from it with some precautions to not get locked in our own channel
switch {
case <- c: // read stale value and put a fresh one
c <- value
default: // consumer have read it - so skip and not get locked
}
}
答案 1 :(得分:1)
package main
import "fmt"
func main() {
// channel buffer must be 1 in this case
var ch = make(chan int, 1)
// when channel was not consumed and you want to update value at channel
produceToChannel(ch, 1)
produceToChannel(ch, 2)
fmt.Println(consumeFromChannel(ch)) // prints 2
// when channel was already consumed and you are producing new value
produceToChannel(ch, 3)
consumeFromChannel(ch)
produceToChannel(ch, 4)
fmt.Println(consumeFromChannel(ch)) // prints 4
}
func produceToChannel(ch chan int, v int) {
select {
case <-ch:
default:
}
ch <- v
}
func consumeFromChannel(ch chan int) int {
return <- ch
}
答案 2 :(得分:0)
每次在向频道发送值之前清除频道。
换句话说,当您发送3%时,3%成为频道中的唯一值。
您可以使用缓冲区长度为1的频道,只需使用<-ch
清除频道即可。
编辑:使用默认情况下的select清除频道<-ch
,因此在前一个值已被读取的情况下不要阻止。
答案 3 :(得分:0)
存储所有入站对象版本的并发映射如何,0表示默认版本
import "sync"
var Versions sync.Map = sync.Map{}
type Data struct {
Payload interface{}
Version int
ID int
}
func produce(c chan Data) {
for {
data := produceData()
if hasNewVersion(data) {
Versions.Store(data.ID, data.Version)
}
c <- data
}
}
func consume(c chan Data) {
for {
select {
case val:= <- c:
if ver, ok := Versions.Load(val.ID); ok {
if ver.(int) == val.Version {
// process
}
}
}
}
}