Skip to content

golangci-lint パフォーマンス調査 ​

目的 ​

golangci-lintの実行が遅い原因を特定するため、二分探索法でlinterを無効化し、ボトルネックとなっているlinterを特定する。

調査環境 ​

  • 日時: 2025-10-01
  • ディレクトリ: /Users/aitaro/works/uzu/app.worktree/-speedup-golangci-lint/backend

有効化されているlinter一覧 ​

yaml
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時間備考
staticcheck73秒124.26s user + 13.22s system🔴 最も遅い
unparam70秒58.22s user + 6.52s system🔴 2番目に遅い
revive43秒61.60s user + 11.33s system🟠 3番目に遅い
unused40秒50.98s user + 4.32s system🟠 4番目に遅い
bodyclose36秒47.88s user + 4.48s system🟠 遅い
containedctx35秒41.58s user + 3.65s system🟠 遅い
govet35秒46.93s user + 5.21s system🟠 遅い
gocritic34秒44.13s user + 6.20s system🟠 遅い
copyloopvar33秒61.72s user + 2.67s system🟠 遅い
depguard1.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秒

yaml
disable:
  - staticcheck
  - unparam
  - revive
  - unused
  - bodyclose
  - containedctx
  - govet
  - gocritic
  - copyloopvar

パターンB: バランス型(推奨) ​

非常に遅いlinterのみ無効化 → 実行時間: 約2-3分

yaml
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です:

  1. staticcheck (73秒) - SSA解析による静的解析で非常に重い
  2. unparam (70秒) - 未使用パラメータの検出で全関数を解析
  3. revive (43秒) - 多数のルール設定により重い
  4. unused (40秒) - 未使用コード検出で全体を解析

これら4つだけで 約3分46秒 を占めています。

開発体験を向上させるには、これらのlinterを無効化するか、CI/CDでのみ実行する設定に変更することを強く推奨します。