猿问

Golang 清除通道外不会被读取的项目

我正在处理一个 http 端点,它将接收来自客户端的请求并阻塞,直到它从另一台服务器收到该请求的“确认”或直到它通过超时。我的代码和服务器之间的通信未包含在此示例中,但您可以假设对于每个请求,最终可能会收到一个 ack。


由于许多请求将在短时间内通过我的模块,我不能假设给定的 ack 与我阻止的请求相关。编辑:在这里澄清,因为它引起了一些混乱。控制器从外部来源接收请求和确认。这就是我异步处理它们的原因。/EDIT出于这个原因,如果它们不相关,我的代码会将 acks 放回通道。同样重要的是要注意 http.ListenAndServe 异步调用我的函数。


如果请求在超时内被确认,则没有问题。但是,如果 ack 在超时过后出现,它将被添加到通道中并且永远不会被删除。这将导致通道被填满。我害怕使用“取消”通道,因为也有可能不会收到给定请求的 ack,从而导致取消通道也被填满。


问题:如何防止延迟确认填充我的频道?/如何识别和删除延迟确认?


代码如下。没有 play.golang.org 链接,因为 http.ListenAndServe :/


package main


import (

    "fmt"

    "net/http"

    "time"

)


const timeout = 10


func startEndpoint(w http.ResponseWriter, r *http.Request) {

    var ack string

    timer := time.NewTimer(time.Second * timeout)

    defer timer.Stop()


    m := r.RequestURI[len("/start/"):]

    fmt.Print(m)

AckRecycle:

    for {

        select {

        case ack = <-acks:

            if ack == m {

                //What we found was our own ack

                fmt.Print("+")

                w.Write([]byte("Ack received for " + ack))

                break AckRecycle

            } else {

                //What we found on the channel wasn't for us

                fmt.Print(".")

                time.Sleep(time.Millisecond * 100)

                acks <- ack

            }

        case <-timer.C:

            //We ran out of time waiting for our ack

            w.Write([]byte("Timeout waiting for " + m))

            break AckRecycle

        default:

            //Channel was empty

            fmt.Print("-")

            time.Sleep(time.Millisecond * 100)

        }

    }

    return

}


func ackEndpoint(w http.ResponseWriter, r *http.Request) {

    ack := r.RequestURI[len("/ack/"):]

    acks <- ack

    fmt.Print("Ack for " + ack)

    w.Write([]byte("Thanks!"))

    return

}


注意:要对此进行测试,请在本地计算机上运行它。Curl/Wget127.0.0.1:8888/start/bob然后是 Curl/Wget 127.0.0.1:8888/ack/bob。您可以用任何字符串替换 bob 以查看行为。


我是 Go 的新手。请随时在评论中提供其他反馈。


慕尼黑的夜晚无繁华
浏览 270回答 2
2回答

ITMISS

保持一个map“uuids in process”;当您收到一个/start/将其添加到地图时,以及当您收到一个ack(或请求超时时)将其删除时。如果您收到不在地图中的确认,请立即丢弃它。小心,因为默认情况下映射不是线程安全的。

桃花长相依

看起来您可能正在尝试以 Akka 的异步风格编写 Go。这是一个艰难的选择;惯用的 Go 应该更容易。缺陷在这里:“我不能假设给定的 ack 与我阻止的请求相关”。相反,您需要使用简单的顺序步骤处理每个请求,并将 ack 直接发送回其客户端。为此,每个请求都需要自己的服务 goroutine。
随时随地看视频慕课网APP

相关分类

Go
我要回答