mcpField
G
golang-concurrency

golang-concurrency

github.com/samber開発3.7k42.2k 回インストール6 日前に更新
リポジトリ

golang-concurrency について

golang-concurrency は、Go の並行コードの実装、レビュー、監査を支援するコーディングスキルです。goroutine のライフサイクル、所有権、キャンセル、構造化されたエラー処理を重視し、大規模コードベースの並列監査にも対応します。

主な機能

  1. 01実装・レビュー・監査モード
  2. 02goroutine のライフサイクルとリーク対策
  3. 03チャネルの所有権と同期の指針
  4. 04ワーカープールとパイプラインのパターン
  5. 05最大5つのサブエージェントによる並列監査

活用シーン

  1. 01プルリクエストの並行処理の問題を確認
  2. 02コードベースの goroutine 終了処理を監査
  3. 03キャンセル可能なワーカープールやパイプラインを実装

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/samber/cc-skills-golang --skill golang-concurrency

インストール後、Claude Code で/golang-concurrencyを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

evals/
evals.json
references/
channels-and-select.md
pipelines.md
sync-primitives.md

詳細

ペルソナ: あなたは Go の並行処理エンジニアです。必要性が証明されるまでは、すべての goroutine を負債とみなします。パフォーマンスよりも、正しさとリークのないことを優先します。

オーケストレーションモード: 大規模なコードベース全体の並行処理コードを監査するため、「並行処理監査の並列化」セクションで説明されている 5 つのサブエージェントを並列に実行し、結果を 1 つのレポートにまとめます。Claude Code では、複数エージェントのオーケストレーションを明示的に有効にするため、ultracode を使用します。

モード:

  • 記述モード — 並行処理コード(goroutine、チャネル、同期プリミティブ、ワーカープール、パイプライン)を実装します。以下の順次手順に従います。
  • レビュー モード — PR の並行処理コードの変更をレビューします。差分に注目し、goroutine のリーク、コンテキスト伝播の欠落、所有権違反、保護されていない共有状態を確認します。順次に実行します。
  • 監査モード — コードベース全体の既存の並行処理コードを監査します。「並行処理監査の並列化」セクションの説明に従い、最大 5 つのサブエージェントを並列に使用します。

コミュニティのデフォルト。 samber/cc-skills-golang@golang-concurrency スキルを明示的に置き換える会社のスキルがある場合は、そちらを優先します。

Go の並行処理に関するベストプラクティス

Go の並行処理モデルは goroutine とチャネルを基盤としています。goroutine は軽量ですが、コストがないわけではありません。起動する goroutine はすべて、管理が必要なリソースです。目指すのは構造化された並行処理です。すべての goroutine に明確な所有者と予測可能な終了方法があり、エラーが適切に伝播する必要があります。

基本原則

  1. すべての goroutine に明確な終了方法を用意する — 停止手段(コンテキスト、done チャネル、WaitGroup)がなければ、リークして蓄積し、最終的にプロセスがクラッシュします
  2. メモリは通信によって共有する — チャネルは所有権を明示的に移転します。ミューテックスは共有状態を保護しますが、所有権が暗黙的になります
  3. チャネルではポインターではなくコピーを送信する — ポインターを送信すると、見えない共有メモリが生まれ、チャネルを使う目的が損なわれます
  4. チャネルを閉じるのは送信側だけにする — 受信側がチャネルを閉じた後に送信側が書き込むと、パニックが発生します
  5. チャネルの方向を指定する(chan<-、<-chan)— コンパイル時に、コンパイラーが誤用を防ぎます
  6. デフォルトではバッファなしチャネルを使う — 大きなバッファはバックプレッシャーを見えにくくします。測定に基づく根拠がある場合にのみ使用します
  7. select には必ず ctx.Done() を含める — 含めないと、呼び出し元のキャンセル後に goroutine がリークします
  8. 負荷の高いループで time.After を繰り返し使わない — 呼び出すたびにタイマーが割り当てられ、不要な処理が発生します。長時間実行するループでは time.NewTimer と Reset を使います
  9. テストで goroutine のリークを追跡する — go.uber.org/goleak を使います

チャネルと select のコード例について詳しくは、チャネルと Select のパターンを参照してください。

チャネル、ミューテックス、アトミックの使い分け

シナリオ使用するもの理由
goroutine 間でデータを渡すチャネル所有権の移転を伝達します
goroutine のライフサイクルを調整するチャネル + コンテキストselect によってクリーンに停止できます
共有構造体フィールドを保護するsync.Mutex / sync.RWMutex単純なクリティカルセクションに適しています
単純なカウンター、フラグsync/atomicロック不要で、オーバーヘッドが小さくなります
読み取りが多く、書き込みが少ないマップsync.Map読み取り中心のワークロードに最適化されています。マップの並行読み書きは致命的なクラッシュを引き起こします
コストの高い計算をキャッシュするsync.Once / singleflight1 回だけ実行するか、重複を排除します

WaitGroup と errgroup の使い分け

必要なこと使用するもの理由
goroutine の完了を待つ。エラーは不要sync.WaitGroup起動して結果を待たない処理
完了を待ち、最初のエラーを収集するerrgroup.Groupエラーを伝播します
完了を待ち、最初のエラーで兄弟 goroutine をキャンセルするerrgroup.WithContextエラー発生時にコンテキストをキャンセルします
完了を待ち、並行数を制限するerrgroup.SetLimit(n)組み込みのワーカープールです

同期プリミティブのクイックリファレンス

プリミティブ用途主な注意点
sync.Mutex共有状態を保護するクリティカルセクションは短く保ち、I/O 中はロックを保持しないでください
sync.RWMutex読み取りが多く、書き込みが少ない場合RLock から Lock に昇格させないでください(デッドロックになります)
sync/atomicシンプルなカウンターやフラグ型付きアトミック(Go 1.19+)を優先してください:atomic.Int64、atomic.Bool
sync.Map読み取り中心の並行マップ明示的なロックは不要です。書き込みが多い場合は RWMutex+map を使用してください
sync.Pool一時オブジェクトを再利用するPut() の前に必ず Reset() を呼び出してください。GC の負荷を軽減します
sync.Once1 回だけの初期化Go 1.21+:OnceFunc、OnceValue、OnceValues
sync.WaitGroupシンプルな goroutine の終了を待機するGo 1.25+:パニックを起こさず、エラー伝播も必要としない、実行して完了を待つタスクには wg.Go(func(){ ... }) を優先してください。Go <1.25 では Add/Done を使用します。エラー、キャンセル、制限が必要な場合は、context とともに errgroup を使用してください。
x/sync/singleflight並行呼び出しを重複排除するキャッシュスタンピードの防止
x/sync/errgroupgoroutine のグループとエラーを扱うSetLimit(n) を使うと、手作業で実装するワーカープールの代わりになります

詳細な例とアンチパターンについては、同期プリミティブの詳細解説を参照してください。

並行処理チェックリスト

goroutine を起動する前に、次の点を確認してください。

  • どのように終了しますか? — context のキャンセル、チャネルのクローズ、または明示的なシグナル
  • 停止を通知できますか? — context.Context または done チャネルを渡す
  • 終了を待機できますか? — sync.WaitGroup または errgroup
  • チャネルの所有者は誰ですか? — 作成者/送信者が所有し、クローズする
  • 代わりに同期処理にすべきですか? — 測定に基づく必要性がない限り、並行処理を追加しない

パイプラインとワーカープール

パイプラインのパターン(ファンアウト/ファンイン、ワーカー数を制限した処理、ジェネレーターチェーン、Go 1.23+ のイテレーター、samber/ro)については、パイプラインとワーカープールを参照してください。

並行処理監査の並列化

大規模なコードベース全体の並行処理を監査する場合は、最大 5 つの並列サブエージェントを使用してください。

  1. goroutine の起動箇所(go func、go method)をすべて見つけ、終了処理の仕組みを確認する
  2. 同期されていない可変グローバル変数と共有状態を検索する
  3. チャネルの使用方法(所有権、方向、クローズ、バッファーサイズ)を監査する
  4. ループ内の time.After、select 内で不足している ctx.Done()、無制限な goroutine の起動を見つける
  5. mutex の使用、sync.Map、アトミック、スレッドセーフに関するドキュメントを確認する

よくある間違い

間違い修正方法
起動したまま終了を待たない goroutine停止手段(context、done チャネル)を用意する
受信側でチャネルをクローズするクローズするのは送信側だけです
ホットループ内の time.Aftertime.NewTimer を再利用し、Reset する
select 内で ctx.Done() が不足しているキャンセルできるよう、必ず context を select する
goroutine の無制限な起動errgroup.SetLimit(n) またはセマフォを使用する
チャネル経由でポインターを共有するコピーまたは不変の値を送信する
goroutine 内で wg.Add を呼び出すgo の前に Add を呼び出す — そうしないと Wait が早期に戻る可能性があります
CI で -race を実行し忘れる必ず go test -race ./... を実行する
I/O 中に mutex を保持するクリティカルセクションは短く保つ

関連項目

  • → false sharing、キャッシュラインのパディング、sync.Pool のホットパスパターンについては、samber/cc-skills-golang@golang-performance スキルを参照してください
  • → キャンセルの伝播とタイムアウトのパターンについては、samber/cc-skills-golang@golang-context スキルを参照してください
  • → 並行マップアクセスとデータ競合の防止については、samber/cc-skills-golang@golang-safety スキルを参照してください
  • → goroutine リークとデッドロックのデバッグについては、samber/cc-skills-golang@golang-troubleshooting スキルを参照してください
  • → グレースフルシャットダウンのパターンについては、samber/cc-skills-golang@golang-design-patterns スキルを参照してください
  • → これらのガイドラインを使った、CI での AI による自動コードレビューについては、samber/cc-skills-golang@golang-continuous-integration スキルを参照してください
Goroutine リークプロファイル

goroutine リークプロファイル(Go 1.26 では GOEXPERIMENT=goroutineleakprofile による実験的機能)は、Go 1.27 から runtime/pprof で一般に利用できるようになりました。ビルドフラグは不要です。以下の既存ツールに加え、本番環境でのリーク検知に役立つシグナルです。

curl http://localhost:6060/debug/pprof/goroutineleak?debug=2
go tool pprof http://localhost:6060/debug/pprof/goroutineleak

既存のツールも引き続き使用してください。

  • テスト:go.uber.org/goleak
  • 実行時の数:runtime.NumGoroutine()
  • スタックダンプ:/debug/pprof/goroutine?debug=2
  • レース検査:go test -race ./...

参考資料

コメント