为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
慕尼黑的夜晚无繁华 2021-09-13 09:44:21
我正在处理一个 http 端点,它将接收来自客户端的请求并阻塞,直到它从另一台服务器收到该请求的“确认”或直到它通过超时。我的代码和服务器之间的通信未包含在此示例中,但您可以假设对于每个请求,最终可能会收到一个 ack。由于许多请求将在短时间内通过我的模块,我不能假设给定的 ack 与我阻止的请求相关。编辑:在这里澄清,因为它引起了一些混乱。控制器从外部来源接收请求和确认。这就是我异步处理它们的原因。/EDIT出于这个原因,如果它们不相关,我的代码会将 acks 放回通道。同样重要的是要注意 http.ListenAndServe 异步调用我的函数。如果请求在超时内被确认,则没有问题。但是,如果 ack 在超时过后出现,它将被添加到通道中并且永远不会被删除。这将导致通道被填满。我害怕使用“取消”通道,因为也有可能不会收到给定请求的 ack,从而导致取消通道也被填满。问题:如何防止延迟确认填充我的频道?/如何识别和删除延迟确认?代码如下。没有 play.golang.org 链接,因为 http.ListenAndServe :/package mainimport (    "fmt"    "net/http"    "time")const timeout = 10func 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 的新手。请随时在评论中提供其他反馈。
查看完整描述

2 回答

?
ITMISS

TA贡献1871条经验 获得超8个赞

保持一个map“uuids in process”;当您收到一个/start/将其添加到地图时,以及当您收到一个ack(或请求超时时)将其删除时。如果您收到不在地图中的确认,请立即丢弃它。

小心,因为默认情况下映射不是线程安全的。


查看完整回答
反对 回复 2021-09-13
?
桃花长相依

TA贡献1860条经验 获得超8个赞

看起来您可能正在尝试以 Akka 的异步风格编写 Go。这是一个艰难的选择;惯用的 Go 应该更容易。缺陷在这里:“我不能假设给定的 ack 与我阻止的请求相关”。

相反,您需要使用简单的顺序步骤处理每个请求,并将 ack 直接发送回其客户端。为此,每个请求都需要自己的服务 goroutine。


查看完整回答
反对 回复 2021-09-13
  • 2 回答
  • 0 关注
  • 269 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信