From 4896f963f7475ea6c09226e3c4d9b6f06caa4877 Mon Sep 17 00:00:00 2001 From: Andrii Chebukin Date: Mon, 3 Aug 2026 02:33:07 +0200 Subject: [PATCH 1/2] Perf: add CancellableTask.whenAllThrottled to cap parallel typechecks in Find All References (#20127) --- .../FSharp.Editor/Common/CancellableTasks.fs | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/vsintegration/src/FSharp.Editor/Common/CancellableTasks.fs b/vsintegration/src/FSharp.Editor/Common/CancellableTasks.fs index 5056ddee461..e067c7f6408 100644 --- a/vsintegration/src/FSharp.Editor/Common/CancellableTasks.fs +++ b/vsintegration/src/FSharp.Editor/Common/CancellableTasks.fs @@ -1098,6 +1098,28 @@ module CancellableTasks = return! Task.WhenAll (tasks) } + /// Runs the given tasks concurrently, but caps the number of tasks that are running at + /// the same time to at most maxDegreeOfParallelism, to avoid launching an unbounded number + /// of parallel typechecks (e.g. one per document/project) at once. + let inline whenAllThrottled maxDegreeOfParallelism (tasks: CancellableTask<'a> seq) = + cancellableTask { + let! ct = getCancellationToken () + use semaphore = new SemaphoreSlim(maxDegreeOfParallelism: int) + + let runThrottled (task: CancellableTask<'a>) = + backgroundTask { + do! semaphore.WaitAsync(ct) + + try + return! start ct task + finally + semaphore.Release() |> ignore + } + + let tasks = seq { for task in tasks do yield runThrottled task } + return! Task.WhenAll (tasks) + } + let inline whenAllTasks (tasks: CancellableTask seq) = cancellableTask { let! ct = getCancellationToken () From 149109eabf34cf59d3a0db411799ef3ef04a2fe3 Mon Sep 17 00:00:00 2001 From: Andrii Chebukin Date: Mon, 3 Aug 2026 02:34:25 +0200 Subject: [PATCH 2/2] Perf: throttle parallel typechecks in Find All References (#20127) --- .../src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs b/vsintegration/src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs index c7eb1e50e41..a9825587e94 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs @@ -1,4 +1,4 @@ -[] +[] module internal Microsoft.VisualStudio.FSharp.Editor.WorkspaceExtensions open System @@ -707,7 +707,8 @@ type Project with documents |> Seq.map (fun doc -> doc.FindFSharpReferencesAsync(symbol, projectSnapshot, (fun range -> onFound doc range), userOpName)) - |> CancellableTask.whenAll + // Throttle to avoid launching a typecheck per document in the project all at once. + |> CancellableTask.whenAllThrottled (max 1 Environment.ProcessorCount) else for doc in documents do do! doc.FindFSharpReferencesAsync(symbol, projectSnapshot, (onFound doc), userOpName)