DirSize整数累加无需精度控制,因int64字节求和零误差;精度问题实际发生在BytesToMB单位换算时,需用整数缩放或math.Round避免float64表示误差。

DirSize 函数本身不涉及浮点运算,所以“累计求和精度控制”在目录大小计算场景里是个伪命题——你真正要处理的,是整数累加的溢出风险和单位换算时的舍入误差。
如果你看到别人在 Go 里对 int64 求和后还谈“精度控制”,大概率是混淆了场景:比如把字节数转成 MB 时用 float64 做除法,再四舍五入到小数点后两位。这步才是精度控制的主战场,不是求和本身。
为什么 int64 累加不需要“精度控制”
文件大小以字节为单位,fs.FileInfo.Size() 返回 int64,而 int64 最大值约 9.2E18 字节(≈ 8 EiB),远超单机文件系统实际容量。只要不手动转成 float64 再做加法,就不存在精度丢失。
- 错误做法:
size += int64(float64(info.Size()) * 1.0)—— 引入不必要的浮点转换 - 正确做法:
size += info.Size()—— 原生整数累加,零误差 - 并发安全前提:确保
size是函数内局部变量,别用全局或指针共享
BytesToMB 单位换算时的舍入控制
把总字节数转成 MB 并保留两位小数,本质是整数 → 浮点 → 格式化输出的过程。关键在如何避免 float64 表示误差导致的显示偏差(比如本该显示 123.45 却变成 123.44999999999999)。
- 不要用
fmt.Sprintf("%.2f", float64(bytes)/1024/1024)——float64无法精确表示大多数十进制小数 - 推荐用整数缩放 + 四舍五入:
(bytes * 100 / (1024 * 1024))得到“百分之一 MB”的整数值,再除以 100.0 - 更稳妥:用
math.Round(float64(bytes)/1024/1024*100) / 100,但需注意math.Round对负数行为(不过文件大小恒 ≥ 0)
并发调用 DirSize 时的隐性陷阱
即使每个调用都用局部变量,若你在外部用 goroutine 并发跑多个 DirSize,还要注意底层 filepath.Walk 的实现细节:
-
filepath.Walk本身不是并发安全的——它不保证遍历顺序,但也不禁止并发调用;问题出在 OS 层:大量并发stat系统调用可能触发内核锁或磁盘 I/O 队列拥塞 - 实测发现:并发 16 个
DirSize调用,总耗时可能比串行慢 3–5 倍,尤其在机械硬盘或 NFS 上 - 解决思路不是加锁,而是限流:用带缓冲的 channel 控制同时活跃的遍历 goroutine 数量(如 4 个)
真正容易被忽略的点是:单位换算那一步,开发者常直接扔给 fmt 或 strconv 处理,却没意识到浮点二进制表示的固有缺陷。哪怕只是显示用,一旦涉及财务、配额告警等场景,.01 MB 的偏差就可能触发误报。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











