当前位置: 首页 > news >正文

Go 1.26 新特性:net.Dialer 终于支持 Context,还做了性能优化!

大家好,我是煎鱼。

我们在写 Go 网络编程代码时,net包几乎是绕不开的。不管是写 HTTP 客户端,还是搞 TCP/UDP 服务端,连接(Dial)这个动作大家都很熟悉。

但社区里一直有个不大不小的 “痛点”,就是居然不支持 Context,简直 “奇葩“ 的很。

今天我们就来聊聊 Go1.26 的新特性Context-aware Dialer methods,将能够解决这个问题。

尴尬的现状:效率与控制的左右互搏

我们先得回顾一下现在的 Go 标准库是怎么处理网络连接的。

假设你现在是一个 Sidecar 代理,或者是一个高性能的 RPC 客户端。你从服务发现中心拿到了一个目标 IP 和端口。

如果你想建立连接,你通常面临两个选择,而且都很尴尬:

选择 A:使用旧时代的 Specific 函数

你可以调用net.DialTCP

func DialTCP(network string, laddr, raddr *TCPAddr) (*TCPConn, error)
  • 优点:它非常快。你传给它的是*TCPAddr,它可以直接拿着 IP 去做系统调用,跳过了 DNS 解析,也跳过了 Go 内部对network字符串的解析和分发。

  • 缺点它不支持 Context。这意味着,如果网络卡住了,或者上层业务取消了请求,这个连接操作没法立刻感知并取消。在微服务架构里,“不能取消” 往往意味着资源泄漏和级联故障的风险。

选择 B:使用通用的 Dialer

为了解决 Context 的问题,大家后来都转向了net.Dialer

func (d *Dialer) DialContext(ctx context.Context, network, address string) (Conn, error)
  • 优点:完美支持context.Context,超时控制、级联取消一气呵成。

  • 缺点它有点 “笨”。即使你手里已经有了 IP,你也得把它转成字符串(比如"10.0.0.1:8080")传进去。DialContext内部会拿这个字符串再去跑一遍解析逻辑(Resolver),判断它是 TCP 还是 UDP,甚至可能尝试重新做 DNS 查询。

对于每秒几万、几十万连接的高频场景,这种反复解析和字符串转换,都是实打实的 CPU 消耗。

所以现有的情况就是:想要高性能,就得裸奔(没 Context);想要安全(有 Context),就得忍受冗余开销。

这就很尴尬。

新提案:Context,全都要加

为了解决这个问题,社区大佬 @neko 提出了新的提案《net: add context-aware Dialer methods DialTCP, DialUDP, DialIP, DialUnix[1]》,并且推进了实现。

核心思路非常简单粗暴:net.Dialer加上那些缺失的、带 Context 的特定网络方法。

在本地 Go1.26 新版本中,net.Dialer结构体将新增以下四个方法:

  • DialTCP

  • DialUDP

  • DialIP

  • DialUnix

性能优化:拥抱 netip

这里有个非常值得注意的技术细节。

老的一代函数(如net.DialTCP)接收的是*net.TCPAddr。但熟悉 Go 历史的同学都知道,net.IP底层是一个[]byte,它是可变的,而且容易导致逃逸到堆上,给 GC 造成压力。

新的提案非常机智,它直接拥抱了net/netip包。这是 Go 官方近年来力推的新一代 IP 地址库,基于值类型(Value Type),也就是netip.Addrnetip.AddrPort

看看新方法的签名(以 TCP 为例):

// 看看这个入参:netip.AddrPort // 这意味着更少的内存分配,更高效的栈上拷贝 func (d *Dialer) DialTCP(ctx context.Context, network string, laddr, raddr netip.AddrPort) (*TCPConn, error)

这波改动,不仅解决了 Context 的问题,顺带还把性能优化的最佳实践给固化下来了。

实战代码演示

接下来我们看下,等这个特性落地后(预计 Go 1.26),代码该怎么写。

TCP 连接示例

假设你已经拿到了目标 IP 和端口,使用netip构建地址并连接:

package main import ( "context" "log" "net" "net/netip" "time" ) func main() { var d net.Dialer // 设置 5 秒超时 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() // 模拟构建一个目标地址,这里使用 netip 包 // 假设我们要连本地的 12345 端口 raddr := netip.MustParseAddrPort("127.0.0.1:12345") // 直接调用新的 DialTCP 方法 // 注意:这里跳过了 DNS 解析,直接发起 TCP 连接 conn, err := d.DialTCP(ctx, "tcp", netip.AddrPort{}, raddr) if err != nil { // 因为我本地没起服务,这里肯定会报错 log.Fatalf("Failed to dial: %v", err) } defer conn.Close() if _, err := conn.Write([]byte("Hello, World!")); err != nil { log.Fatal(err) } }

Unix Socket 示例

对于 Unix Socket,因为它不涉及 IP 地址,所以签名里用的还是老的*net.UnixAddr

func main() { var d net.Dialer ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() raddr := &net.UnixAddr{Name: "/path/to/unix.sock", Net: "unix"} // 连接 Unix Socket conn, err := d.DialUnix(ctx, "unix", nil, raddr) if err != nil { log.Fatalf("Failed to dial: %v", err) } defer conn.Close() // ... }

性能敏感的值得一看

对于做网关、做数据库驱动、做 RPC 框架的开发者来说,本次特性帮助非常大。

比如 @fraenkel 和 @neko (提案作者) 就强调:在高性能场景下,我们手里拿到的通常就是 IP 地址(比如从 K8s Endpoints 里拿到的)。

这种场景下,强制转换成字符串再去解析,在逻辑上就是不合理的。也会存在隐性解析失败风险。

netip 的全面上位

还有一个隐性的趋势被大家热议,就是netip包正在逐步接管net包的底层数据结构。

以前大家写代码满天飞的net.IP,现在官方都在暗示你:“别用了,那个慢,容易 GC,用netip吧。”这次Dialer的新方法直接绑定netip,也算是官方的一种强力表态。

总结

这次net.Dialer的更新,虽然看起来只是加了几个方法,但本质上是 Go 网络编程接口演进的一个缩影。

  • Context 是必须的:任何网络 IO 操作都应该接受 Context 管辖,这一点已经成为共识。

  • 性能是不妥协的:Go 还是那个追求高性能的 Go,对于底层库的 overhead 依然是锱铢必较。

  • 类型系统在进步:从net.IPnetip.Addr,Go 正在通过更好的类型设计来减少 GC 压力。

目前这个提案将会在 Go 1.26 版本和大家见面,RC1 版本中已有。基本稳妥了。

参考资料

[1]

net: add context-aware Dialer methods DialTCP, DialUDP, DialIP, DialUnix:https://github.com/golang/go/issues/49097

关注和加煎鱼微信,

一手消息和知识,拉你进技术交流群👇

你好,我是煎鱼,出版过 Go 畅销书《Go 语言编程之旅》,再到获得 GOP(Go 领域最有观点专家)荣誉,点击蓝字查看我的出书之路

日常分享高质量文章,输出 Go 面试、工作经验、架构设计,加微信拉读者交流群,和大家交流!

原创不易 点赞支持

http://www.jsqmd.com/news/163029/

相关文章:

  • Anaconda虚拟环境中安装PyTorch的三种可靠方式
  • NVIDIA Profile Inspector终极配置指南:让老游戏重获新生的秘密武器
  • 高速PCB层间切换信号完整性处理方案
  • PyTorch-CUDA-v2.9镜像对A100/H100显卡的支持情况
  • Conda安装PyTorch总是失败?试试这个稳定镜像方案
  • PyTorch-CUDA-v2.9镜像运行风格迁移Style Transfer
  • PyTorch-CUDA-v2.9镜像支持Diffusion模型文生图
  • 中规院 :2025年中国主要城市通勤监测报告 2
  • fastboot驱动与主机操作系统集成方法
  • PyTorch-CUDA-v2.9镜像兼容性测试报告:覆盖RTX 30/40系列
  • vivado2018.3安装步骤与工控机兼容性配置说明
  • PyTorch-CUDA-v2.9镜像支持文本纠错Grammarly类功能
  • 继电器模块电路图核心要点:从原理到应用全面讲解
  • NVIDIA显卡隐藏性能深度挖掘:从入门到精通的实战宝典
  • 基于Spring Boot的宠物商城网站设计与实现
  • Packet Tracer官网下载Linux支持情况解析
  • PyTorch DataLoader与GPU显存大小的关系分析
  • 解锁隐藏显卡性能:NVIDIA Profile Inspector完全配置指南
  • PyTorch-CUDA-v2.9镜像助力智能客服意图识别
  • PyTorch安装教程GPU版:手把手教你配置高效深度学习环境
  • 如何快速转换NCM文件:终极使用指南
  • 重组抗体:基因工程赋能的生物医学 “万能工具”,重塑科研与临床应用格局
  • 绝对值的性质和可视化
  • 深度剖析SPICE中BJT Gummel-Poon模型的应用
  • 炉石传说插件HsMod完整使用指南:55项功能快速上手
  • SPICE仿真下的二极管伏安特性核心要点
  • 2025年度海外猎头公司深度测评报告:全球化人才布局的优质伙伴甄选指南 - 短商
  • PyTorch-CUDA-v2.9镜像助力智能客服大模型训练
  • 证件阅读机以 “多证兼容、全场景适配” 的核心优势,构建了覆盖银行核心业务的服务网络,让跨境客户享受无差别的便捷服务
  • PyTorch-CUDA-v2.9镜像用于Stable Diffusion图像生成