ネットワークを利用するプログラムを作成すると、CGO_ENABLED=0
を使用したコンパイルのかなりの速度低下が見られます。
たとえば、最も単純な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)
}
}
タイミングは次のとおりです。
% 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
これまでのところ、Cへのバインディングを使用していないため、CGoの処理は無関係であるように見えますが、100%の静的バイナリをコンパイルすることをお勧めしますが、そのような速度低下がある場合はそうしません。
そのような行動の原因は何ですか?
問題は、標準ライブラリパッケージがフラグなしでビルドされていることです。 CGO_ENABLED
はビルドフラグを変更するため、ビルド済みのパッケージを使用できないため、ほとんどの標準ライブラリを再ビルドする必要があります。
他の回答が述べたように、go build -i
は新しいフラグでビルドされたパッケージをインストールしますが、CGO_ENABLED=0
でビルドされたパッケージをインストールすると、将来のすべてのビルドが高速化されるため、実際にはそれほど解決しませんCGO_ENABLED=0
、しかしそれなしではすべてのビルドが遅くなります。
残念ながら、今日の既定のビルド済みパッケージのインストール方法は、ビルド方法に関係なく、すべてが同じ名前で同じディレクトリに入るので、かなり非効率的です。異なるフラグを持つgoプログラムの高速ビルドを可能にしたい場合は、go build -i
を実行する以外に、-installsuffix
フラグまたは-pkgdir
フラグも使用する必要があります。私が作業しているシステムでは、いくつかの異なるコンパイルモードがあり、各モードにはさまざまなフラグがあります(インターフェイスとなる古いCコードがたくさんあるため)。各モードにも独自の-pkgdir
があります。
これは、依存関係の再構築に費やされた時間です。デフォルトでGoビルドは、再構築された依存関係を保存しません。 -i
フラグを参照してください:The -i flag installs the packages that are dependencies of the target.
代わりに-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
初めてcgoモードを切り替えるときは、依存関係を再構築する必要があります。 -i
を指定すると、それらが保存され、2番目のビルド呼び出しがはるかに速くなります。