Use a buffered channel as a semaphore to limit the number of active goroutines. Create a channel with the desired capacity, send a token before starting work, and receive a token when finished.
limit := make(chan struct{}, 10) // Allow 10 concurrent goroutines
for _, task := range tasks {
limit <- struct{}{} // Acquire token
go func(t string) {
defer func() { <-limit }() // Release token
doWork(t)
}(task)
}