技术圈开发者交流群:

Go 语言中 nil channel:动态控制 select 分支

Go 并发代码中,经常需要让同一个 goroutine 在不同阶段监听不同事件:任务未启动时不接收数据,队列为空时不向下游发送,某个输入关闭并排空后不再关注它。

最直接的做法是为每种状态编写一套 select,但分支一多,代码很快变成重复的状态判断。Go 其实提供了一个简洁的控制手段:在进入下一轮 select 前把某个 channel 变量设为 nil,就能让对应的 case 暂时失效;恢复为有效 channel,分支又会在后续求值时重新启用。

这个技巧没有特殊语法,完全建立在 channel 的基本语义之上,却很适合实现状态机、多路合并与背压控制。

GoLang 前天 1005

Go 并发测试不再靠 Sleep:testing/synctest 实践

测试并发代码时,经常能看到一种熟悉的写法:启动 goroutine,调用 time.Sleep 等一会儿,再检查结果。

问题在于,“等一会儿”没有可靠定义。休眠太短,CI 负载升高时测试会偶发失败;休眠太长,又会拖慢整个测试套件。涉及超时和定时器时,测试甚至可能真的等待几十秒。

Go 1.25 将 testing/synctest 转为稳定的标准库 API。它通过虚拟时间和明确的同步点,让并发测试摆脱对机器调度速度的依赖。

GoLang 前天 178

反射也能用迭代器了:Go 1.26 Type.Fields 与 Value.Fields 解析

反射常用于解析标签、生成配置和实现序列化工具。过去遍历字段,需要先调用 NumField,再按索引获取。

Go 1.26 为 reflect.Typereflect.Value 增加了 Fields 方法。它没有改变反射规则,但让字段遍历更直接。

传统写法需要手动维护索引:

GoLang 11天前 686

Go 优雅退出新姿势:获取 NotifyContext 的取消原因

部署 Go 服务时,经常能在退出日志中看到一句 server stopped: context canceled

它说明 Context 已经取消,却没有回答最关键的问题:程序究竟收到了用户按下 Ctrl+C 产生的 SIGINT,还是容器平台发来的 SIGTERM?前者可能是开发者主动结束程序,后者则可能来自滚动发布、Pod 驱逐或系统关机。

Go 1.26 改进了 signal.NotifyContext。由系统信号触发取消时,开发者可以通过 context.Cause 获取包含信号信息的原因,退出日志不必再只剩一句含糊的 context canceled

GoLang 12天前 186

Go 测试产物放哪里?ArtifactDir 给出标准答案

写单元测试时,断言通常足以说明代码对不对。但进入接口测试、图片测试或模糊测试后,仅有一句“测试失败”往往不够。

开发者可能需要保留原始 JSON、实际截图或诊断报告。过去,这些文件要么污染项目目录,要么藏在难以寻找的临时目录中。Go 1.26 新增的 ArtifactDir,为测试产物提供了统一的存放方式。

Go 1.26 为普通测试、基准测试和模糊测试提供了 T.ArtifactDirB.ArtifactDirF.ArtifactDir

GoLang 13天前 896

Go 项目中 GOMAXPROCS 还需要手动设置吗?

部署 Go 服务时,经常能看到这样的启动参数:

GOMAXPROCS=2 ./server

很多开发者把它理解成“限制程序只能使用两个 CPU”,也有人习惯直接调用 runtime.GOMAXPROCS(runtime.NumCPU())。但在容器环境里,宿主机可能有 64 个逻辑 CPU,而容器只被分配 2 核额度。如果 Go 运行时仍按 64 设置并行度,程序就可能频繁触发 CPU 限流,最终表现为接口尾延迟突然升高。

GoLang 06月06日 200

Go 语言中 HTTP 响应体为什么必须关闭?

一道看似基础、却很容易暴露工程习惯的 Go 面试题是:调用 http.Getclient.Do 拿到响应后,为什么总要写 defer resp.Body.Close()

有人会回答“防止内存泄漏”,也有人会回答“为了复用连接”。方向并非完全错误,但还不够准确:响应体本质上连接着网络数据流,关闭是调用方的责任;对于默认客户端使用的 HTTP/1.x 持久连接,想让连接更可能被下一次请求复用,通常还要把响应体读取到结束再关闭。

这个小细节会直接影响接口调用、爬虫采集和批处理任务的稳定性。

GoLang 05月28日 1009

面试题:Go 语言中的切片 append 后为什么时变时不变?

一道常见的 Go 面试题是:把切片传给函数,在函数里执行 append,调用方的数据会不会改变?

回答“切片是引用类型,所以会变”,或者“Go 只有值传递,所以不会变”,都不完整。这个细节在参数拼装、权限列表、查询过滤条件中经常造成偶发覆盖。通过几段短代码,就能把它变成开发中真正有用的小技巧。

先看一个最简单的函数,它试图给列表追加一个元素:

GoLang 05月27日 682

Go语言中如何优雅比较切片?别再无脑用 DeepEqual 了!

在 Go 语言中,切片(Slice)不能使用 == 直接进行比较(除与 nil 对比外)。因此,当需要判断两个切片是否相等时,开发者通常需要在反射方案、手写循环以及 Go 1.21 新增的 slices 泛型工具包方案中进行抉择。这篇文章将结合 Benchmark 压测,深度对比这三种方式的实现原理与性能差异。

在 Go 1.18 引入泛型之前,要想写出一个通用的切片比较函数,通常只能求助于标准库的反射机制:

import "reflect"

// 使用 reflect.DeepEqual 比较切片
func compareWithReflect(a, b []int) bool {
    return reflect.DeepEqual(a, b)
}
GoLang 05月26日 196

Go 语言 context.Value 的强类型安全实践

写 Go 的时候,很多开发者天天都在和 context.Context 打交道。这玩意儿本来是设计用来传取消信号和控制超时的,但实际开发里,很多人喜欢把 context.Value 当成『全局垃圾桶』,啥东西都往里塞:DB 连接、各种 Config、甚至业务控制参数。这不仅让 API 接口变得很不透明,还在运行时埋了一堆类型安全的坑。这篇文章就来聊聊 context.Value 怎么用才不会翻车。

最典型的反面教材,就是把 *gorm.DB 这种数据库连接,或者全局 Config 直接通过 Context 往下传:

func SaveUser(ctx context.Context, u *User) error {
    db := ctx.Value("db").(*gorm.DB) // 从上下文中读取连接
    return db.Create(u).Error
}
GoLang 05月20日 692

排行

解决方案

网站建设

专业企业官网建设,塑造企业形象,传递企业价值

系统开发

系统软件开发,用心思考,用心设计,用心体验

技术支撑

打破技术瓶颈,让不堪重负的项目起死回生

业务中台

构建全渠道一体化运营能力,实现全链路数字化

文案策划

文案撰写、营销策划,专注品牌全案

新媒体运营

一站式解决企业互联网营销痛点和难题

以技术的力量,改变互联网

联系我们
鄂ICP备19028750号-1 @copyright 2026 tech1024.com