From 2f9df911718b13ca86386d0a95016c17bd45d0da Mon Sep 17 00:00:00 2001 From: Junegunn Choi Date: Thu, 26 Feb 2026 14:51:59 +0900 Subject: [PATCH] Add --threads option to control matcher concurrency By default, fzf uses 8 * NumCPU goroutines (capped at 32) for parallel matching. --threads N overrides this to use exactly N goroutines, which is useful for benchmarking and profiling. --- src/core.go | 2 +- src/matcher.go | 5 ++++- src/options.go | 8 ++++++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/core.go b/src/core.go index 6c453082..3d31bed9 100644 --- a/src/core.go +++ b/src/core.go @@ -235,7 +235,7 @@ func Run(opts *Options) (int, error) { opts.Fuzzy, opts.FuzzyAlgo, opts.Extended, opts.Case, opts.Normalize, forward, withPos, opts.Filter == nil, nth, opts.Delimiter, inputRevision, runes, denylistCopy, headerLines) } - matcher := NewMatcher(cache, patternBuilder, sort, opts.Tac, eventBox, inputRevision) + matcher := NewMatcher(cache, patternBuilder, sort, opts.Tac, eventBox, inputRevision, opts.Threads) // Filtering mode if opts.Filter != nil { diff --git a/src/matcher.go b/src/matcher.go index eb22abd8..14af1088 100644 --- a/src/matcher.go +++ b/src/matcher.go @@ -54,8 +54,11 @@ const ( // NewMatcher returns a new Matcher func NewMatcher(cache *ChunkCache, patternBuilder func([]rune) *Pattern, - sort bool, tac bool, eventBox *util.EventBox, revision revision) *Matcher { + sort bool, tac bool, eventBox *util.EventBox, revision revision, threads int) *Matcher { partitions := min(numPartitionsMultiplier*runtime.NumCPU(), maxPartitions) + if threads > 0 { + partitions = threads + } return &Matcher{ cache: cache, patternBuilder: patternBuilder, diff --git a/src/options.go b/src/options.go index fc055968..ba314c05 100644 --- a/src/options.go +++ b/src/options.go @@ -678,6 +678,7 @@ type Options struct { WalkerSkip []string Version bool Help bool + Threads int Bench time.Duration CPUProfile string MEMProfile string @@ -3375,6 +3376,13 @@ func parseOptions(index *int, opts *Options, allArgs []string) error { return err } opts.WalkerSkip = filterNonEmpty(strings.Split(str, ",")) + case "--threads": + if opts.Threads, err = nextInt("number of threads required"); err != nil { + return err + } + if opts.Threads < 0 { + return errors.New("--threads must be a positive integer") + } case "--bench": str, err := nextString("duration required (e.g. 3s, 500ms)") if err != nil {