标准库中 http.Request 中 WithContext 方法为什么要浅拷贝一次而不是直接赋值? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
macscsbf
V2EX  &nbs; Go 编程语言

标准库中 http.Request 中 WithContext 方法为什么要浅拷贝一次而不是直接赋值?

  •  
  •   macscsbf 2023 年 3 月 6 日 2635 次点击
    这是一个创建于 1106 天前的主题,其中的信息可能已经有所发展或是发生改变。

    如题。

    // WithContext returns a shallow copy of r with its context changed // to ctx. The provided ctx must be non-nil. // // For outgoing client request, the context controls the entire // lifetime of a request and its response: obtaining a connection, // sending the request, and reading the response headers and body. // // To create a new request with a context, use NewRequestWithContext. // To make a deep copy of a request with a new context, use Request.Clone. func (r *Request) WithContext(ctx context.Context) *Request { if ctx == nil { panic("nil context") } r2 := new(Request) *r2 = *r r2.ctx = ctx return r2 } 
    9 条回复    2023-03-14 20:55:47 +08:00
    aladdinding
        1
    aladdinding  
       2023 年 3 月 6 日
    我也有这个问题诶
    fgwmlhdkkkw
        2
    fgwmlhdkkkw  
       2023 年 3 月 6 日
    不改变之前的引用的行为。
    aladdinding
        3
    aladdinding  
       2023 年 3 月 6 日
    在 net/http 标准库中,http.Request 中的 WithContext 方法会返回一个新的 http.Request 对象,它会将原始的请求对象复制一份,然后将新的上下文信息赋值给新的请求对象。这样做的原因是为了确保新的请求对象与原始请求对象是完全独立的,以避免在并发处理请求时可能出现的竞争条件。

    具体来说,WithContext 方法会浅拷贝一份原始请求对象的所有字段,包括头部、URL 、请求体等等。然后它会将新的上下文信息赋值给新的请求对象的上下文字段,这个操作是通过直接赋值来完成的。因为上下文信息通常只是一个指针类型的数据结构,因此它的复制是非常快速和低成本的,因此可以直接进行赋值操作。

    通过浅拷贝一份请求对象,可以确保新的请求对象与原始请求对象是独立的。这意味着对新的请求对象的任何修改都不会影响原始请求对象,反之亦然。这在处理并发请求时非常重要,因为多个并发请求可能会同时修改同一个请求对象,这可能会导致不可预料的结果。通过确保每个请求对象都是独立的,可以避免这种情况的发生,从而提高程序的稳定性和可靠性。

    FROM ChatGPT
    Frankcox
        4
    Frankcox  
       2023 年 3 月 6 日
    ranleng
        5
    ranleng  
       2023 年 3 月 6 日
    > Request is explicitly immutable. That's why we have Request.WithContext.
    lesismal
        6
    lesismal  
       2023 年 3 月 6 日   2
    @Frankcox 我来啦,感谢 at !

    当初提这个 pr 是因为我的 nbio 实现的 http 兼容标准库,这涉及到 Request 的 context 字段,每个请求的 context 应该是共用一个全局的,这样当全局的 context 退出(比如进程退出、cancel 时),这个 request 的 handler 中使用这个 context 就可以一块退出(比如使用 Mysql 时传入这个 context )。但这个字段不是导出的,所以没有办法直接设置。

    由于标准库规则严格、不肯开放这个字段导出,至少对于官方而言,他们不考虑 nbio 要解决的海量并发连接数写成数量、内存开销、GC 等问题,所以官方也确实不需要开放导出。

    无奈只能使用魔法了,预先用 WithContext 生成了一个带有公共 context 的 Request ,后面创建新 Request 时 *newReq = *reqWithCtx 整体赋值,就避过没导出不能设置的问题了。不过虽然能用,毕竟 Request 结构体有点大,这么做能用但不划算,凑合用吧,毕竟我也支持官方不随意放权。。。 :joy:
    macscsbf
        7
    macscsbf  
    OP
       2023 年 3 月 7 日
    @aladdinding 谢谢
    zizon
        8
    zizon  
       2023 年 3 月 14 日
    @lesismal 那 cancel 单个不是会导致影响其他?
    lesismal
        9
    lesismal  
       2023 年 3 月 14 日
    @zizon
    单个请求,为什么会想到去 cancel 全局的呢?
    单个请求自己 return 就完事了,除非这是运维发出的停止服务之类的请求。是不是这个理?嘿嘿
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     932 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 27ms UTC 21:47 PVG 05:47 LAX 14:47 JFK 17:47
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86