KDOC 713: gofmtはバッファ付きチャネルで同時に開くファイルの数を制限する
この文書のステータス
- 作成
- 2026-10-18 貴島
- レビュー
- 2026-10-18 貴島
概要
gofmtは、バッファ付きチャネルをセマフォとして使い、同時に開くファイルの数を200までに制限している。ファイルを開く前にチャネルへ値を送り、閉じたら受け取る。バッファが埋まっていると送信がブロックするので、201個目のファイルは、どれかが閉じるまで開かれない。
https://github.com/golang/go/blob/e3336a22ad3f0a90bd252c95d8b5544e02674205/src/cmd/gofmt/gofmt.go#L61-L69
// fdSem guards the number of concurrently-open file descriptors.
//
// For now, this is arbitrarily set to 200, based on the observation that many
// platforms default to a kernel limit of 256. Ideally, perhaps we should derive
// it from rlimit on platforms that support that system call.
//
// File descriptors opened from outside of this package are not tracked,
// so this limit may be approximate.
var fdSem = make(chan bool, 200)
https://github.com/golang/go/blob/e3336a22ad3f0a90bd252c95d8b5544e02674205/src/cmd/gofmt/gofmt.go#L302-L319
// readFile reads the contents of filename, described by info.
// If in is non-nil, readFile reads directly from it.
// Otherwise, readFile opens and reads the file itself,
// with the number of concurrently-open files limited by fdSem.
func readFile(filename string, info fs.FileInfo, in io.Reader) ([]byte, error) {
if in == nil {
fdSem <- true
var err error
f, err := os.Open(filename)
if err != nil {
return nil, err
}
in = f
defer func() {
f.Close()
<-fdSem
}()
}
関連
抽象。
- 容量の限られた入れ物を使って、同時に動く数を制限する
関連。
- 疑問: 制限がないとどうなるか
- 疑問: Linter によって違いはあるか
- 対比: KDOC 279: パイプのバッファはいっぱいになるとwriteをブロックする。どちらも満杯で書き込みが待つ。パイプはデータを運ぶが fdSem は中身を使わず空きの数だけ使う
- 類似: KDOC 663: リングキューは満杯になるといちばん古い要素を上書きする。決まった大きさの入れ物に出し入れする
- 類推: KDOC 660: Performance InsightsでCPUの負荷がvCPUの線を超えるとCPU不足である。同時に処理できる数に上限があり、超えた分は待たされる例