Через sync.WaitGroup: перед запуском wg.Add(n), в горутине в конце defer wg.Done(), затем wg.Wait(). Либо канал: горутина в конце пишет в канал или закрывает его, основная читает. Либо errgroup.Group.
var wg sync.WaitGroup
for i := 0; i < n; i++ { wg.Add(1); go func() { defer wg.Done(); work() }() }
wg.Wait()