Skip to content

Commit b63942a

Browse files
committed
Perf: Refactor whenAllThrottled for clearer resource handling
Refactored the `whenAllThrottled` function to use an array of background tasks, ensuring each acquires/releases the semaphore properly. Explicitly disposes the semaphore after all tasks complete using a continuation on `Task.WhenAll`. Simplified the XML doc comment. This replaces the previous sequence expression and `use` binding with more robust disposal logic.
1 parent 09eb3bd commit b63942a

1 file changed

Lines changed: 26 additions & 16 deletions

File tree

‎vsintegration/src/FSharp.Editor/Common/CancellableTasks.fs‎

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1098,26 +1098,36 @@ module CancellableTasks =
10981098
return! Task.WhenAll (tasks)
10991099
}
11001100

1101-
/// Runs the given tasks concurrently, but caps the number of tasks that are running at
1102-
/// the same time to at most maxDegreeOfParallelism, to avoid launching an unbounded number
1103-
/// of parallel typechecks (e.g. one per document/project) at once.
1101+
/// Runs the given tasks concurrently, but caps concurrent work to maxDegreeOfParallelism.
11041102
let inline whenAllThrottled maxDegreeOfParallelism (tasks: CancellableTask<'a> seq) =
11051103
cancellableTask {
11061104
let! ct = getCancellationToken ()
1107-
use semaphore = new SemaphoreSlim(maxDegreeOfParallelism: int)
1108-
1109-
let runThrottled (task: CancellableTask<'a>) =
1110-
backgroundTask {
1111-
do! semaphore.WaitAsync(ct)
1112-
1113-
try
1114-
return! start ct task
1115-
finally
1116-
semaphore.Release() |> ignore
1117-
}
1105+
let semaphore = new SemaphoreSlim(maxDegreeOfParallelism: int)
1106+
1107+
let started =
1108+
[|
1109+
for task in tasks do
1110+
backgroundTask {
1111+
do! semaphore.WaitAsync(ct)
1112+
1113+
try
1114+
return! start ct task
1115+
finally
1116+
semaphore.Release() |> ignore
1117+
}
1118+
|]
1119+
1120+
let allTask = Task.WhenAll started
1121+
1122+
allTask.ContinueWith(
1123+
(fun (_: Task<'a[]>) -> semaphore.Dispose()),
1124+
CancellationToken.None,
1125+
TaskContinuationOptions.ExecuteSynchronously,
1126+
TaskScheduler.Default
1127+
)
1128+
|> ignore
11181129

1119-
let tasks = seq { for task in tasks do yield runThrottled task }
1120-
return! Task.WhenAll (tasks)
1130+
return! allTask
11211131
}
11221132

11231133
let inline whenAllTasks (tasks: CancellableTask seq) =

0 commit comments

Comments
 (0)