我正在尝试在Go中构建服务,该服务会将实时流(socketio / signalR)延迟约7分钟。它还应允许不延迟的流。因此,Go服务应具有类似于缓冲区或队列的内容,以强制数据等待指定的持续时间后才被允许使用。您将如何在Go中做这样的事情?延迟流将成为单独的goroutine吗?应该使用什么数据结构来延迟数据?
我当前的想法是使用time
包在允许消费数据之前等待/滴答7分钟,但是这种阻塞行为在这种情况下可能不是最佳的。
这里有一些代码来解释我要做什么。 FakeStream
是一个模拟函数,可以模拟我从外部服务获取的实时流数据。
package main
import (
"fmt"
"time"
)
func DelayStream(input chan string, output chan string, delay string) {
// not working for some reason
// delayDuration, _ := time.ParseDuration(delay)
// fmt.Println(delayDuration.Seconds())
if delay == "5s" {
fmt.Println("sleeping")
time.Sleep(5 * time.Second)
}
data := <-input
output <- data
}
func FakeStream(live chan string) {
ticks := time.Tick(2 * time.Second)
for now := range ticks {
live <- fmt.Sprintf("%v", now.Format(time.UnixDate))
}
}
func main() {
liveData := make(chan string)
delayedData := make(chan string)
go FakeStream(liveData)
go DelayStream(liveData, delayedData, "5s")
for {
select {
case live := <-liveData:
fmt.Println("live: ", live)
case delayed := <-delayedData:
fmt.Println("delayed: ", delayed)
}
}
}
由于某些原因,延迟的通道仅输出一次,并且不输出预期的数据。它应该在直播频道中输出第一件事,但不会。
答案 0 :(得分:3)
您需要一个足够大小的缓冲区。对于简单的情况,可以使用缓冲的Go频道。
问自己-在此延迟期间要存储多少数据-您应该有一个合理的上限。例如,如果您的流每秒传输多达N个数据包,那么要延迟7分钟,您将需要存储420N个数据包。
问问自己-如果在延迟窗口中到达的数据比预期的多,该怎么办?您可以丢弃新数据,或丢弃旧数据,或仅阻止输入流。其中哪种对您的方案可行?每种方法都会导致略有不同的解决方案。
问自己-延迟如何计算?从创建流的那一刻起?从每个数据包到达的那一刻起?是每个数据包的延迟是单独的还是仅流中的第一个数据包的延迟?
您需要在此处缩小设计范围,以开发一些示例代码。
对于这些设计选择的某些子集,这是一种增加每种消息的通道之间延迟的简单方法:
package main
import (
"fmt"
"sync"
"time"
)
func main() {
// in is a channel of strings with a buffer size of 10
in := make(chan string, 10)
// out is an unbuffered channel
out := make(chan string)
// this goroutine forwards messages from in to out, ading a delay
// to each message.
const delay = 3 * time.Second
go func() {
for msg := range in {
time.Sleep(delay)
out <- msg
}
close(out)
}()
var wg sync.WaitGroup
wg.Add(1)
// this goroutine drains the out channel
go func() {
for msg := range out {
fmt.Printf("Got '%s' at time %s\n", msg, time.Now().Format(time.Stamp))
}
wg.Done()
}()
// Send some messages into the in channel
fmt.Printf("Sending '%s' at time %s\n", "joe", time.Now().Format(time.Stamp))
in <- "joe"
time.Sleep(2 * time.Second)
fmt.Printf("Sending '%s' at time %s\n", "hello", time.Now().Format(time.Stamp))
in <- "hello"
time.Sleep(4 * time.Second)
fmt.Printf("Sending '%s' at time %s\n", "bye", time.Now().Format(time.Stamp))
in <- "bye"
close(in)
wg.Wait()
}