@@ -61,8 +61,6 @@ type Orchestrator struct {
6161 tasks * collections.SyncMap [tspath.Path , * BuildTask ]
6262 order []string
6363 errors []* ast.Diagnostic
64- // Semaphore to limit concurrent builds
65- buildSemaphore chan struct {}
6664
6765 errorSummaryReporter tsc.DiagnosticsReporter
6866 watchStatusReporter tsc.DiagnosticReporter
@@ -240,14 +238,9 @@ func (o *Orchestrator) Watch() {
240238func (o * Orchestrator ) updateWatch () {
241239 oldCache := o .host .mTimes
242240 o .host .mTimes = & collections.SyncMap [tspath.Path , time.Time ]{}
243- wg := core .NewWorkGroup (o .opts .Command .CompilerOptions .SingleThreaded .IsTrue ())
244- o .tasks .Range (func (path tspath.Path , task * BuildTask ) bool {
245- wg .Queue (func () {
246- task .updateWatch (o , oldCache )
247- })
248- return true
241+ o .rangeTask (func (path tspath.Path , task * BuildTask ) {
242+ task .updateWatch (o , oldCache )
249243 })
250- wg .RunAndWait ()
251244}
252245
253246func (o * Orchestrator ) resetCaches () {
@@ -263,20 +256,14 @@ func (o *Orchestrator) DoCycle() {
263256 var needsConfigUpdate atomic.Bool
264257 var needsUpdate atomic.Bool
265258 mTimes := o .host .mTimes .Clone ()
266- wg := core .NewWorkGroup (o .opts .Command .CompilerOptions .SingleThreaded .IsTrue ())
267- o .tasks .Range (func (path tspath.Path , task * BuildTask ) bool {
268- wg .Queue (func () {
269- if updateKind := task .hasUpdate (o , path ); updateKind != updateKindNone {
270- needsUpdate .Store (true )
271- if updateKind == updateKindConfig {
272- needsConfigUpdate .Store (true )
273- }
259+ o .rangeTask (func (path tspath.Path , task * BuildTask ) {
260+ if updateKind := task .hasUpdate (o , path ); updateKind != updateKindNone {
261+ needsUpdate .Store (true )
262+ if updateKind == updateKindConfig {
263+ needsConfigUpdate .Store (true )
274264 }
275- })
276- // Watch for file changes
277- return true
265+ }
278266 })
279- wg .RunAndWait ()
280267
281268 if ! needsUpdate .Load () {
282269 o .host .mTimes = mTimes
@@ -307,11 +294,9 @@ func (o *Orchestrator) buildOrClean() tsc.CommandLineResult {
307294 var buildResult orchestratorResult
308295 if len (o .errors ) == 0 {
309296 buildResult .statistics .Projects = len (o .Order ())
310- if o .opts .Command .CompilerOptions .SingleThreaded .IsTrue () {
311- o .singleThreadedBuildOrClean (& buildResult )
312- } else {
313- o .multiThreadedBuildOrClean (& buildResult )
314- }
297+ o .rangeTask (func (path tspath.Path , task * BuildTask ) {
298+ o .buildOrCleanProject (task , path , & buildResult )
299+ })
315300 } else {
316301 // Circularity errors prevent any project from being built
317302 buildResult .result .Status = tsc .ExitStatusProjectReferenceCycle_OutputsSkipped
@@ -325,25 +310,40 @@ func (o *Orchestrator) buildOrClean() tsc.CommandLineResult {
325310 return buildResult .result
326311}
327312
328- func (o * Orchestrator ) singleThreadedBuildOrClean (buildResult * orchestratorResult ) {
329- // Go in the order since only one project can be built at a time so that random order isnt picked by work group creating deadlock
330- for _ , config := range o .Order () {
313+ func (o * Orchestrator ) rangeTask (f func (path tspath.Path , task * BuildTask )) {
314+ numRoutines := 4
315+ if o .opts .Command .CompilerOptions .SingleThreaded .IsTrue () {
316+ numRoutines = 1
317+ } else if builders := o .opts .Command .BuildOptions .Builders ; builders != nil {
318+ numRoutines = * builders
319+ }
320+
321+ var currentTaskIndex atomic.Int64
322+ getNextTask := func () (tspath.Path , * BuildTask , bool ) {
323+ index := int (currentTaskIndex .Add (1 ) - 1 )
324+ if index >= len (o .order ) {
325+ return "" , nil , false
326+ }
327+ config := o .order [index ]
331328 path := o .toPath (config )
332329 task := o .getTask (path )
333- o .buildOrCleanProject (task , path , buildResult )
330+ return path , task , true
331+ }
332+ runTask := func () {
333+ for path , task , ok := getNextTask (); ok ; path , task , ok = getNextTask () {
334+ f (path , task )
335+ }
334336 }
335- }
336337
337- func (o * Orchestrator ) multiThreadedBuildOrClean (buildResult * orchestratorResult ) {
338- // Spin off the threads with waiting on upstream to build before actual project build
339- wg := core .NewWorkGroup (false )
340- o .tasks .Range (func (path tspath.Path , task * BuildTask ) bool {
341- wg .Queue (func () {
342- o .buildOrCleanProject (task , path , buildResult )
343- })
344- return true
345- })
346- wg .RunAndWait ()
338+ if numRoutines == 1 {
339+ runTask ()
340+ } else {
341+ wg := core .NewWorkGroup (false )
342+ for range numRoutines {
343+ wg .Queue (runTask )
344+ }
345+ wg .RunAndWait ()
346+ }
347347}
348348
349349func (o * Orchestrator ) buildOrCleanProject (task * BuildTask , path tspath.Path , buildResult * orchestratorResult ) {
@@ -398,9 +398,5 @@ func NewOrchestrator(opts Options) *Orchestrator {
398398 } else {
399399 orchestrator .errorSummaryReporter = tsc .CreateReportErrorSummary (opts .Sys , opts .Command .Locale (), opts .Command .CompilerOptions )
400400 }
401- // If we want to build more than one project at a time, create a semaphore to limit concurrency
402- if builders := opts .Command .BuildOptions .Builders ; builders != nil {
403- orchestrator .buildSemaphore = make (chan struct {}, * builders )
404- }
405401 return orchestrator
406402}
0 commit comments