go http.Request.Conn.ActiveConn是一个映射,所以它会有并发映射问题吗?

go http.Request.Conn.ActiveConn是一个映射,所以它会有并发映射问题吗?,go,Go,go http.Request.Context.ActiveConn是一个映射,它会有并发映射问题吗 如果有很多连接,我会打印包含ActiveConnmap的request.Context,它会有并发读写映射问题吗 package main import ( "fmt" "net/http" ) func main() { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {

go http.Request.Context.ActiveConn是一个映射,它会有并发映射问题吗

如果有很多连接,我会打印包含ActiveConnmap的request.Context,它会有并发读写映射问题吗

package main

import (
    "fmt"
    "net/http"
)

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "r.ctx: %#v, %+v", r.Context(), r.Context())
    })
    http.ListenAndServe(":1234", nil)
}

我使用webench进行压力测试,由于并发映射问题,它将失败。那么,有没有人有同样的问题?因为这个,我把核心服务搞砸了

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

这里发生的事情是,当在那里打印整个r.Context时,您最终访问了Go服务器对象的内部字段,而没有同步对它的访问

这将导致您最终看到的并发映射读取和映射写入错误

最简单的解决方案是替换此选项:

fmt.Fprintf(w, "r.ctx: %#v, %+v", r.Context(), r.Context())
使用您编写的某个自定义函数,该函数接受该上下文对象并提取与您相关的值,例如,您自己添加到上下文中的任何自定义键/值

有关activeConn字段的更详细说明

在打印整个r.Context时看到的activeConn来自Go的服务器类型

准备侦听连接时,服务器会创建一个基本上下文,在其中添加对服务器本身的引用:

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

服务器实现在需要使用该映射时同步对该映射的访问,例如:


您看到的是*http.Server的未导出activeConn字段。当然,使用反射来绕过任何同步来读取该字段不会得到正确的同步。我个人不同意您的消息,即用户有责任做额外的事情来打印一些值,特别是当它已经满足字符串接口时。所以,它看起来真的像一只虫子。我已经测试过简单的处理程序,它使用ab-c100-n1000处理fmt.Fprintfw,%s,r.Context。。。但它失败了。我很确定,这是一种未定义和不受欢迎的行为。@tacobot:这里唯一看起来有点像bug的是,用户可以通过反射读取未报告的字段,但这是一个设计决策,此时无法更改。如果您打算绕过任何同步方法来读取结构的未报告内部内容,那么您就有权决定是否可以。@Jimb同意!但是,这是一个糟糕的设计决定。只是我的意见。@tacobot,我的回答指出了问题的原因以及如何解决它,并解释了这不是Go的http实现本身的并发问题,而是打印上下文引起的,如果这是一个错误或不是在这个问题的范围之外。如果需要,可以向Go的项目报告@张todd,我不认为静态工具会检测到这一点,但您可以在启用种族检测器的情况下运行测试:,因此一种方法是创建一个并发调用处理程序的测试,并在启用种族检测的情况下运行它
func (srv *Server) Serve(l net.Listener) error {
    ....
    ctx := context.WithValue(baseCtx, ServerContextKey, srv)
    ....
}
activeConn map[*conn]struct{}
...

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)
}
....