发布于 2026-01-06 8 阅读
0

为什么 Go 模块比 GOPATH 更快?DEV 的全球展示挑战赛由 Mux 呈现:展示你的项目!

为什么 Go 模块比 GOPATH 更快

由 Mux 主办的 DEV 全球展示挑战赛:展示你的项目!

使用 Go 模块下载依赖项的速度比使用基于 GOPATH 的依赖管理方式要快得多GOPATH。本文中,我们进行了一次全新的依赖项下载实验,GOPATH 模式耗时 9 分 33.845 秒,而模块模式仅需 10.185 秒。本文将解释其中的原因。关键区别在于,模块避免了深度仓库克隆,并且可以使用模块代理。

有关 Go 模块的介绍,请参阅https://blog.golang.org/using-go-modules

GOPATH基于依赖项的管理会将每个依赖项下载到 中GOPATH/src,在此过程中对版本控制存储库进行深度克隆。

所以,如果你处于GOPATH这种模式,并且你的项目依赖于 A,A 依赖于 B,B 依赖于 C,那么该go命令将对git clone所有三个存储库进行操作(假设它们都使用 git)。

使用 Go 模块时,下载依赖项时需要两样东西:

  1. 依赖项的源代码。
  2. 依赖项go.mod文件。

go.mod文件用于确定您需要的每个依赖项的版本。go命令收集完go.mod所有依赖项的所有文件后,即可确定您的项目所需的每个依赖项的版本。

例如,如果您直接依赖模块 A 和模块 B,而模块 A 又依赖于模块 B 的 v1.2.0 版本,那么您的模块至少需要依赖于模块B 的 v1.2.0 版本。这个原则同样适用于您直接或间接依赖的每个模块。

依赖关系图显示了 A 对 B v1.2.0 的依赖关系,这意味着您的项目必须至少依赖 B v1.2.0。

附注:请注意,如果模块 A 或 B 发布了新版本,您所需的 B 模块最低版本要求不会改变。该要求长期保持稳定。

模块代理

模块代理是 Go 模块速度如此之快的关键原因之一。模块代理能够理解每个模块依赖项所需的两个组成部分:源代码和文件go.mod。这种理解带来了两项独立的优化:

  1. 源代码可以以 ZIP 文件的形式分发,而无需进行深度版本控制系统克隆。下载单个 ZIP 文件比进行完整的版本控制系统克隆要快得多,这使得模块下载比 GOPATH 更高效。
  2. 您可以下载单个go.mod文件而无需获取其余源代码。这使得使用模块代理比不使用代理更高效。

优化#1意味着当go命令下载依赖项时,需要下载的内容比以前少GOPATH。该命令无需(通常)执行完整的下载git clonego而是下载一个包含您请求的模块版本源代码的单个zip文件。

如果您使用的模块没有代理,该go命令会尽可能执行浅克隆。浅克隆比深克隆快得多,因为它只检索单个提交,而不是完整的仓库历史记录。

结果是,使用模块时,需要下载的东西比使用其他方式要少得多GOPATH

优化策略之二,即理解go.mod文件,则更为微妙。

模块出现在模块图中并不意味着它也出现在导入图中。模块图包含go.mod文件中所有模块的列表、所有依赖项的文件、这些依赖项go.mod所有依赖项的文件等等。导入图包含项目导入的所有包、这些包导入的包等等。你依赖的模块可能包含一些编译项目并不需要的包。go.mod

例如,假设你依赖一个支持 Postgres、MySQL 和 MongoDB 的数据库辅助工具。该辅助工具为每个支持的数据库都提供了一个单独的包,而每个包又依赖于一个第三方模块/包来与该数据库通信。你的项目只使用了辅助工具的 Postgres 包,因此你不需要 MySQL 或 MongoDB 包来构建项目。此外,你也不需要 MySQL 或 MongoDB 模块的源代码来编译项目——它们不在导入图中!

数据库示例的依赖关系图,其中导入图是模块图的子集。

但是,您确实需要go.mod这些模块的文件。如果某个模块位于您的模块图中,则在确定每个依赖项的最低版本时,必须将其考虑在内。

这时模块代理就派上用场了。模块代理可以提供go.mod给定模块的文件,而无需源代码。如果使用代理,就必须克隆整个仓库(包括源代码)才能获取该go.mod文件,而这样做会导致代码无法编译。值得注意的是,如上所述,go模块模式下的命令会尽可能执行浅克隆。

在这种模式下GOPATHgo命令只会下载导入图中存在的依赖项。因此,这种特定的代理优化仅比不使用模块代理更能提升性能。延迟模块加载go.mod(计划在 Go 1.16 中推出)将通过减少命令需要获取的文件数量来进一步提升模块速度go

结果

上述优化意味着(1)您下载的内容更小,(2)需要下载的内容更少。

综合来看,使用代理下载新模块的速度比不使用代理快约 5 倍。相比之下GOPATH,使用代理下载模块的速度甚至可以快 50 倍以上。

理论上,模块可能会比较慢,因为需要单独下载每个依赖项的版本,而不是像依赖项那样在系统中只保留一个版本。但实际上,模块速度更快,而且缓存占用的磁盘空间更少,尤其是在考虑标准的 GOPATH 和 vendoring 模式时。

试试看

要查看这些优化效果,请尝试使用您选择的依赖项运行以下命令。从 Go 1.13 开始,默认的模块代理是proxy.golang.org——如果您使用的是 Go 1.13 或更高版本,并且使用了模块,也没有进行任何调整GOPROXY,那么您已经可以享受到这些优势了。

我使用Cloud Shell运行了这些测试。您的测试结果可能会因您使用的机器、Go 版本、网络速度、测试依赖项以及其他因素而有所不同。

  1. 首先创建一个临时的、空的GOPATH测试环境,以免删除原有GOPATH内容。

    $ mkdir /tmp/tmp.GOPATH
    $ export GOPATH=/tmp/tmp.GOPATH
    $ go env GOPATH # Just to confirm.
    /tmp/tmp.GOPATH
    
  2. 现在,尝试以下载模式下载依赖项GOPATH。这些命令使用的是cloud.google.com/go/storage,但您可以尝试使用任何您想要的依赖项:

    # Force GOPATH mode. Be sure the current directory
    # doesn't have a go.mod.
    $ export GO111MODULES=off
    $ time go get cloud.google.com/go/storage
    real    9m33.845s
    user    4m1.197s
    sys     0m18.079s
    

    您可以在 GitHub 上找到cloud.google.com/go/storage go.mod文件

  3. 接下来,尝试使用 Go 模块。创建一个新模块进行测试:

    $ mkdir proxy-testing
    $ cd proxy-testing
    $ unset GO111MODULES # Back to the default.
    $ go mod init example.com/proxy-testing
    
  4. 现在,尝试在不使用代理的情况下下载依赖项:

    $ go clean -modcache # Careful!
    $ go env -w GOPROXY=direct # direct means go directly to the source.
    $ go env GOPROXY
    direct
    $ time go get cloud.google.com/go/storage
    go: finding cloud.google.com/go/storage v1.10.0
    ...
    
    real    2m6.396s
    user    1m51.447s
    sys     0m18.311s
    
  5. 现在尝试启用代理(通过重置GOPROXY为默认设置):

    $ go env -w GOPROXY=
    $ go env GOPROXY
    https://proxy.golang.org,direct
    $ go clean -modcache # Careful!
    $ go mod tidy # To start from the same state as before.
    $ time go get cloud.google.com/go/storage
    go: finding cloud.google.com/go/storage v1.10.0
    ...
    
    real    0m10.185s
    user    0m9.610s
    sys     0m1.961s
    

柱状图比较了三个实验的结果。数据汇总如下。

下载cloud.google.com/go/storage耗时:

  • 9分33.845秒(GOPATH模式),
  • 使用模块且不使用代理耗时 2 分 6.396 秒,
  • 10.185 秒,使用带代理的模块(默认)。

如果您在自己的机器上运行这些测试,结果会有所不同。但是,模块的速度要快得多GOPATH,尤其是在使用默认代理时。

文章来源:https://dev.to/tbpalsulich/why-go-modules-are-faster-than-gopath-blj