An interesting point raised is the location of the semaphore block. I previously placed workerChan <- 1 outside the anonymous function so that n number of goroutine workers would start and run at any one time.

But, by placing workerChan <- 1inside the anonymous function right before actual work starts, enables us to fire off all goroutines almost immediately and, subsequently, goroutines will begin work as they become unblocked.

acquire semaphores when you're ready to use them

EDIT(2018-10-06): Although it seemed like a good idea to put the semaphore inside the goroutine, I no longer adopt that pattern.

There are some goroutines working, and potentially many goroutines “idling”. Blocking outside the goroutine as apposed to inside ensures only the working goroutines are consuming resources. More often than not you’ll care about resource consumption instead of the time it takes to “fire up” the next goroutine.