去http.Request.Conn.ActiveConn是一个地图,那么它会有并发地图问题吗?

时间:2019-06-25 15:22:37

标签: go

去http.Request.Context.ActiveConn是一个映射,会不会有并发映射问题?

如果有许多连接,我将打印包含request.Context的{​​{1}},它会不会同时出现读写地图问题?

ActiveConn(map)

我使用Webench进行压力测试,由于并发地图问题,它将失败。那么,有没有人遇到同样的问题呢?因此,我搞砸了核心服务... ...

1 个答案:

答案 0 :(得分:1)

Go的http服务器实现的全部目的是处理并发连接,因此我怀疑您会在实现本身中看到并发问题。

这里发生的事情是,在那里打印整个r.Context()时,您最终访问了Go的Server对象的内部字段,而没有同步对其的访问。

这会导致您最终看到的concurrent map read and map write错误。

最简单的解决方案是替换为:

fmt.Fprintf(w, "r.ctx: %#v, %+v", r.Context(), r.Context())

使用一些自定义函数,您可以编写一个Context对象,并提取与您相关的值(例如,将自己添加到上下文中的任何自定义键/值)。

有关该activeConn字段的详细说明

在打印整个activeConn时看到的r.Context()来自Go的Server类型。

在准备监听连接时,Server创建一个基础上下文,在其中添加对Server本身的引用:

https://github.com/golang/go/blob/master/src/net/http/server.go#L2894

func (srv *Server) Serve(l net.Listener) error {
    ....
    ctx := context.WithValue(baseCtx, ServerContextKey, srv)
    ....
}

因此,在打印整个上下文时,您最终要打印activeConn字段:

https://github.com/golang/go/blob/master/src/net/http/server.go#L2582

activeConn map[*conn]struct{}

Server实现在需要使用该地图时将其同步访问,例如:

https://github.com/golang/go/blob/master/src/net/http/server.go#L2997

...

s.mu.Lock()
defer s.mu.Unlock()
if s.activeConn == nil {
    s.activeConn = make(map[*conn]struct{})
}

if add {
    s.activeConn[c] = struct{}{}
} else {
    delete(s.activeConn, c)
}
....