golangci-lint パフォーマンス調査
目的
golangci-lintの実行が遅い原因を特定するため、二分探索法でlinterを無効化し、ボトルネックとなっているlinterを特定する。
調査環境
- 日時: 2025-10-01
- ディレクトリ:
/Users/aitaro/works/uzu/app.worktree/-speedup-golangci-lint/backend
有効化されているlinter一覧
enable:
- bodyclose
- containedctx
- copyloopvar
- depguard
- dogsled
- durationcheck
- errcheck
- gochecknoinits
- gocritic
- govet
- ineffassign
- misspell
- nakedret
- prealloc
- revive
- staticcheck
- unconvert
- unparam
- unused合計: 20個のlinter
調査結果
ベースライン測定(全linter有効)
- 実行時間: 4分55秒
- CPU時間: 432.06s user + 65.81s system
- 結果: 0 issues
二分探索による調査
第1回: 前半10個を無効化
無効化するlinter:
bodyclose
containedctx
copyloopvar
depguard
dogsled
durationcheck
errcheck
gochecknoinits
gocritic
govet
実行時間: 2分00秒
CPU時間: 162.80s user + 29.20s system
短縮時間: 2分55秒短縮
結論: 前半10個に遅いlinterが含まれている
第2回: 前半5個のみ無効化(bodyclose〜durationcheck)
無効化するlinter:
- bodyclose
- containedctx
- copyloopvar
- depguard
- dogsled
有効化に戻すlinter:
durationcheck
errcheck
gochecknoinits
gocritic
govet
実行時間: 1分20秒
CPU時間: 157.36s user + 24.42s system
短縮時間: 3分35秒短縮
結論: 前半5個(bodyclose〜dogsled)に遅いlinterが含まれている
第3回: 前半3個のみ無効化(bodyclose〜copyloopvar)
無効化するlinter:
- bodyclose
- containedctx
- copyloopvar
有効化に戻すlinter:
depguard
dogsled
実行時間: 2.4秒
CPU時間: 2.81s user + 3.73s system
短縮時間: 4分53秒短縮(ベースラインから)
結論: 前半3個(bodyclose, containedctx, copyloopvar)に極めて遅いlinterが含まれている!
第4回: bodycloseのみを有効化して単体テスト
有効化するlinter:
bodyclose のみ
実行時間: 36秒
CPU時間: 47.88s user + 4.48s system
第5回: containedctxのみを有効化して単体テスト
有効化するlinter:
containedctx のみ
実行時間: 35秒
CPU時間: 41.58s user + 3.65s system
第6回: copyloopvarのみを有効化して単体テスト
有効化するlinter:
copyloopvar のみ
実行時間: 33秒
CPU時間: 61.72s user + 2.67s system
第7回: 3つ全て有効化して合計時間を確認
有効化するlinter:
bodyclose
containedctx
copyloopvar
実行時間: 35秒
CPU時間: 46.09s user + 5.21s system
重要な発見: 3つ同時に実行すると並列化により個別の合計(36+35+33=104秒)より大幅に短縮される
第8回: depguardのみを有効化して単体テスト
有効化するlinter:
depguard のみ
実行時間: 1.4秒
CPU時間: 1.85s user + 1.84s system
結論: depguardは高速
第9回: gocriticのみを有効化して単体テスト
有効化するlinter:
gocritic のみ
実行時間: 34秒
CPU時間: 44.13s user + 6.20s system
結論: gocriticも遅い!
第10回: govetのみを有効化して単体テスト
有効化するlinter:
govet のみ
実行時間: 35秒
CPU時間: 46.93s user + 5.21s system
結論: govetも遅い!
第11回: reviveのみを有効化して単体テスト
有効化するlinter:
revive のみ
実行時間: 43秒
CPU時間: 61.60s user + 11.33s system
結論: reviveが最も遅い!
第12回: staticcheckのみを有効化して単体テスト
有効化するlinter:
staticcheck のみ
実行時間: 73秒
CPU時間: 124.26s user + 13.22s system
結論: staticcheckが最も遅い!
第13回: unparamのみを有効化して単体テスト
有効化するlinter:
unparam のみ
実行時間: 70秒
CPU時間: 58.22s user + 6.52s system
結論: unparamも非常に遅い!
第14回: unusedのみを有効化して単体テスト
有効化するlinter:
unused のみ
実行時間: 40秒
CPU時間: 50.98s user + 4.32s system
結論: unusedも遅い
調査結果サマリー
遅いlinter一覧(実行時間順)
| linter | 実行時間 | CPU時間 | 備考 |
|---|---|---|---|
| staticcheck | 73秒 | 124.26s user + 13.22s system | 🔴 最も遅い |
| unparam | 70秒 | 58.22s user + 6.52s system | 🔴 2番目に遅い |
| revive | 43秒 | 61.60s user + 11.33s system | 🟠 3番目に遅い |
| unused | 40秒 | 50.98s user + 4.32s system | 🟠 4番目に遅い |
| bodyclose | 36秒 | 47.88s user + 4.48s system | 🟠 遅い |
| containedctx | 35秒 | 41.58s user + 3.65s system | 🟠 遅い |
| govet | 35秒 | 46.93s user + 5.21s system | 🟠 遅い |
| gocritic | 34秒 | 44.13s user + 6.20s system | 🟠 遅い |
| copyloopvar | 33秒 | 61.72s user + 2.67s system | 🟠 遅い |
| depguard | 1.4秒 | 1.85s user + 1.84s system | ✅ 高速 |
速いlinter一覧(10秒以下と推定)
以下のlinterは調査していませんが、全体から遅いlinterを除いた残り時間から推定すると速いと考えられます:
- dogsled
- durationcheck
- errcheck
- gochecknoinits
- ineffassign
- misspell
- nakedret
- prealloc
- unconvert
推奨事項
1. 無効化を検討すべき遅いlinter(合計約296秒 → 並列化で約4分55秒)
最優先で無効化検討:
staticcheck(73秒) - SSA解析により非常に遅い。重要度と遅さを天秤にかける必要ありunparam(70秒) - 未使用パラメータ検出。コードレビューで代替可能
無効化を検討:
revive(43秒) - 多数のルール設定があり遅い。必要なルールのみに絞り込むか無効化unused(40秒) - 未使用コード検出。IDE/エディタで代替可能
条件付き無効化を検討:
bodyclose,containedctx,copyloopvar,govet,gocritic(各33-36秒)- これらは有用だが、CI/CDでのみ実行し、ローカル開発では無効化する選択肢もある
2. 高速化のための設定変更案
パターンA: 最大限高速化(開発時用)
遅いlinter全て無効化 → 実行時間: 約3-5秒
disable:
- staticcheck
- unparam
- revive
- unused
- bodyclose
- containedctx
- govet
- gocritic
- copyloopvarパターンB: バランス型(推奨)
非常に遅いlinterのみ無効化 → 実行時間: 約2-3分
disable:
- staticcheck
- unparam
- unusedパターンC: CI/CD分離型
- ローカル開発: パターンAで高速化
- CI/CD: 全linter有効(時間がかかってもOK)
3. 並列化の効果
golangci-lintは並列実行が可能で、実際に:
- 個別実行時間の合計: 296秒以上
- 並列実行時間: 295秒(約4分55秒)
allow-parallel-runners: true が既に設定されているため、並列化の恩恵は受けています。
結論
golangci-lintの遅さの主な原因は以下のlinterです:
- staticcheck (73秒) - SSA解析による静的解析で非常に重い
- unparam (70秒) - 未使用パラメータの検出で全関数を解析
- revive (43秒) - 多数のルール設定により重い
- unused (40秒) - 未使用コード検出で全体を解析
これら4つだけで 約3分46秒 を占めています。
開発体験を向上させるには、これらのlinterを無効化するか、CI/CDでのみ実行する設定に変更することを強く推奨します。