Как синхронизировать горутины?
Горутины синхронизировать/обмениваться данными можно при помощи каналов.
У вас не очень удачный пример для обучения.
Обычно есть горутина или несколько, которые получают данные и пишут их в канал и есть горутина или несколько, которые будут читать из канала.
Читающие горутины будут получать данные из канала в той последовательности, в которой они туда попали.
Ближе к реальности пример будет выглядеть вот так.
Одна горутина пишет данные в канал, а две горутины по очереди извлекают данные.
package main

import (
    "fmt"
    "sync"
    "time"
)

func main() {
    var wg sync.WaitGroup

    num := make(chan int, 1000) // 1000 - размер буффера канала

    wg.Add(1)
    go func() {
        for i := 0; i < 1000; i++ {
            num <- i
            fmt.Printf("write to channel: %d\n", i)
            // задержка нужна только на время теста
            time.Sleep(100 * time.Microsecond)
        }
        close(num)
        wg.Done()
    }()

    wg.Add(1)
    go func() {
        for {
            val, ok := <-num
            if !ok {
                break
            }
            fmt.Printf("goroutine 1 got: %d\n", val)
        }
        wg.Done()
    }()

    wg.Add(1)
    go func() {
        for {
            val, ok := <-num
            if !ok {
                break
            }
            fmt.Printf("goroutine 2 got: %d\n", val)
        }
        wg.Done()
    }()

    wg.Wait()
}
Каналы в го если упрощённо представить то это очереди. Горутины потоки которые воюют за ресурсы и в целом их порядок выполнения можно считать случайно-параллельным в данном примере. Для выведения чисел по порядку в данном случае я бы добавил синхронизирующий примитив на основе мьютекса, который будет следить за очерёдностью использования канала горутинами.