如何延迟直播?

时间:2019-03-08 11:34:29

标签: go

我正在尝试在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)
        }
    }
}

由于某些原因,延迟的通道仅输出一次,并且不输出预期的数据。它应该在直播频道中输出第一件事,但不会。

1 个答案:

答案 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()
}