Golang项目编译速度过慢的优化方案探讨

Golang项目编译速度过慢的优化方案探讨 最近,我的 go build 变得非常慢。 下面的跟踪信息表明,虽然编译本身(exec.Builder.Do)相当快,只用了7秒, 但加载模块(load.PackagesAndErrors)却异常缓慢,耗时31秒!

构建跟踪 (2 MB) - Perfetto UI

大部分时间都花在了:

  • modfetch.download
  • modload.loadImport

这些函数在做什么?我们如何消除它们或加快它们的速度?


更多关于Golang项目编译速度过慢的优化方案探讨的实战教程也可以访问 https://www.itying.com/category-94-b0.html

8 回复

这是一个有趣的发现!差异有多大?

如果可能的话,我也会尝试另一台机器,以排除特定于机器的问题。

更多关于Golang项目编译速度过慢的优化方案探讨的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


我正在运行 go version 命令。

go version go1.20.4 windows/amd64

在我的另一台运行 Go 1.19 的笔记本电脑上,速度几乎相同。

这次更新来得有些晚,也许太晚了,但我想分享这篇关于 Go 构建时间的文章,它可能有助于阐明构建缓慢的原因:

分析 Go 构建时间 | howardjohn 的博客

你当前使用的是哪个版本?我注意到,与我当前的版本相比,构建速度明显比 1.19 慢。以下是我的版本信息:

go version go1.20.4 windows/amd64

如果你也在使用 1.20,可以尝试降级到 1.19。我原以为是我本地安装出了问题,但如果你也遇到了同样的情况,那这可能与 1.20 版本有关?不太确定。

你好,@fumin跟踪链接似乎无法为我打开。我收到一个错误,提示找不到跟踪。

在没有仔细查看的情况下,可能是你的构建下载了大量模块,或者体积很大的模块,并且可能是在一个较慢的网络连接上进行的。你在构建过程中跟踪过网络活动吗?

你好 Christoph,

抱歉,链接似乎是仅限本地的。 我已将跟踪文件上传至:

https://temp-file.org/yXZFItP2p6demoX/file

你可以在 https://ui.perfetto.dev/ 上打开它。

不仔细看的话,可能是你的构建过程下载了大量模块,或者大型模块,可能还是通过慢速连接进行的。

我可以在没有网络的情况下构建我的程序,所以连接问题可以排除。 我知道我笔记本电脑的磁盘速度相当慢,这可能是个问题。 但是,我想知道如何能证实这一点?我推测加载模块确实需要大量的磁盘查找操作?

很难确切地说,因为我之前没有做过任何基准测试,但感觉确实慢了不少。我的开发机器性能相当不错,并且在某些项目中,我使用 cortesi/modd 来监视并持续构建我的 API(类似于使用 preact watch 这样的工具,但用于我的后端),因此我对构建时间的减慢特别敏感。如果通过 vendoring 我的依赖项能解决这个问题,那会很有趣(因为 @fumin 指出大部分时间都花在了 modfetch.download 上)。

对我来说,这只是个小麻烦,正如我提到的,我原本以为是我环境中的某些问题,所以没有花太多时间去排查。而且,如果这是 1.20 版本中的一个退步,几乎可以肯定会在某个时候被发现并修复。

从构建跟踪来看,编译速度慢的主要瓶颈在于模块依赖的下载和加载阶段。modfetch.download 负责下载依赖模块,modload.loadImport 负责解析和加载这些依赖。以下是具体的优化方案:

1. 启用模块缓存持久化

Go 1.15+ 支持模块缓存持久化,可减少重复下载:

# 设置环境变量
export GOMODCACHE=$HOME/.go/modcache
export GOPROXY=direct
export GOSUMDB=off  # 仅测试环境使用,生产环境需谨慎

2. 使用 GOPROXY 加速

配置可靠的代理服务器:

# 使用阿里云代理
go env -w GOPROXY=https://mirrors.aliyun.com/goproxy/,direct
# 或使用官方代理
go env -w GOPROXY=https://proxy.golang.org,direct

3. 预下载依赖

在 CI/CD 或开发环境中预下载所有依赖:

# 下载所有依赖到本地缓存
go mod download
# 并行下载(Go 1.17+)
go mod download -x

4. 优化 go.mod 结构

检查并清理未使用的依赖:

# 整理 go.mod 文件
go mod tidy
# 验证依赖图
go mod verify

5. 使用 vendor 目录

将依赖固化到项目中:

# 创建 vendor 目录
go mod vendor
# 编译时使用 vendor
go build -mod=vendor

6. 升级 Go 版本

Go 1.16+ 改进了模块加载机制:

# 检查当前版本
go version
# 升级到最新稳定版(如 1.21+)

7. 分析依赖树

使用工具识别深层依赖:

# 查看依赖图
go mod graph | head -20
# 使用 go-mod-graph 可视化

示例:完整优化脚本

#!/bin/bash
# 设置优化环境
export GOPROXY=https://mirrors.aliyun.com/goproxy/,direct
export GOMODCACHE=$HOME/.go/cache
export GO111MODULE=on

# 清理并重新下载
go clean -modcache
go mod download

# 使用并行编译
go build -p 8 -v ./...

关键指标验证

优化后可通过以下命令验证:

# 测量构建时间
time go build -v ./...
# 查看模块缓存大小
du -sh $(go env GOMODCACHE)

这些方案能显著减少 modfetch.downloadmodload.loadImport 的执行时间。实际效果取决于网络环境和项目依赖复杂度。

回到顶部