简体   繁体   English

为什么CGO_ENABLED = 0的编译速度较慢?

[英]Why is compiling with CGO_ENABLED=0 slower?

When writing programs which utilize network, you can see quite noticeable slowdown of compilation with CGO_ENABLED=0 . 在编写利用网络的程序时,您可以看到CGO_ENABLED=0的编译速度非常明显。

For example, the simplest HTTP server: 例如,最简单的HTTP服务器:

package main

import (
    "flag"
    "fmt"
    "log"
    "net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hi! glad you requested %s.\n", r.URL.Path[1:])
}

func main() {
    port := flag.Int("port", 9000, "")
    flag.Parse()

    http.HandleFunc("/", handler)
    err := http.ListenAndServe(fmt.Sprintf(":%d", *port), nil)
    if err != nil {
        log.Fatal(err)
    }
}

the timings are: 时间是:

% time go build
go build  0.46s user 0.06s system 131% cpu 0.396 total
% time CGO_ENABLED=0 go build
CGO_ENABLED=0 go build  3.93s user 0.15s system 143% cpu 2.849 total

So far I'm not using bindings to C so CGo handling or not seems irrelevant, what I'd like to do is to compile 100% static binary, but not if there's such slowdown. 到目前为止我没有使用绑定到C所以CGo处理或者似乎不相关,我想要做的是编译100%静态二进制,但如果有这样的减速则不行。

What is the cause of such behavior? 这种行为的原因是什么?

The problem is that the standard library packages are built without flags. 问题是标准库包是在没有标志的情况下构建的。 CGO_ENABLED changes build flags and therefore it can't use the pre-built packages so most of the standard library needs to be rebuilt. CGO_ENABLED更改了构建标志,因此无法使用预构建的包,因此需要重建大部分标准库。

As the other answer mentioned, go build -i will install the packages built with the new flags, but that won't really solve much because if you install packages built with CGO_ENABLED=0 , it will speed up all future builds with CGO_ENABLED=0 , but it will slow down all the builds without it. 正如另一个提到的那样, go build -i将安装使用新标志go build -i的软件包,但这并没有真正解决,因为如果你安装使用CGO_ENABLED=0构建的软件包,它将加速所有未来的构建, CGO_ENABLED=0 ,但如果没有它,它将减慢所有构建。

Unfortunately the way pre-built packages are installed by default today is pretty inefficient because everything goes into the same directory under the same names regardless of how it's built. 不幸的是,今天默认安装预构建软件包的方式是非常低效的,因为无论它是如何构建的,所有内容都以相同的名称进入同一目录。 If you want to be able to have fast builds of go programs with different flags, besides doing go build -i you also need to use the the -installsuffix and/or the -pkgdir flags. 如果你想能够使用不同的标志快速构建go程序,除了go build -i之外,你还需要使用-installsuffix和/或-pkgdir标志。 In the system I work in, we have a handful of different compilation modes, each mode has different flags (because of a lot of old C code we interface with) and each mode also has its own -pkgdir . 在我工作的系统中,我们有一些不同的编译模式,每种模式都有不同的标志(因为我们接口有很多旧的C代码),每种模式也都有自己的-pkgdir

This is the time spent re-building dependencies. 这是重建依赖项所花费的时间。 Go build by default does not save rebuilt dependencies. 默认情况下,Go build不会保存重建的依赖项。 See the -i flag: The -i flag installs the packages that are dependencies of the target. 请参阅-i标志: The -i flag installs the packages that are dependencies of the target.

Let's try your program with -i instead: 让我们用-i尝试你的程序:

$ time go build -i . 
real    0m0.337s
user    0m0.343s
sys 0m0.121s

$ time CGO_ENABLED=0 go build -i .    
real    0m2.135s
user    0m3.098s
sys 0m0.196s

$ time CGO_ENABLED=0 go build .
real    0m0.329s
user    0m0.367s
sys 0m0.085s

$ time go build .    
real    0m2.588s
user    0m3.393s
sys 0m0.300s

The first time you switch cgo mode, it needs to rebuild dependencies. 第一次切换cgo模式时,需要重建依赖关系。 If you specify -i , it will save them and the second build call will be much faster. 如果指定-i ,它将保存它们,第二次构建调用将更快。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM