为什么按通道接收值时看不到输出

in the next example, I don't understand why end value not printed when received

package main

import "fmt"

func main() {
    start := make(chan int)
    end := make(chan int)

    go func() {
        fmt.Println("Start")
        fmt.Println(<-start)
    }()

    go func() {
        fmt.Println("End")
        fmt.Println(<-end)
    }()

    start <- 1
    end <- 2
}

I know sync.WaitGroup can solve this problem.

Because the program exits when it reaches the end of func main, regardless of whether any other goroutines are running. As soon as the second function receives from the end channel, main's send on that channel is unblocked and the program finishes, before the received value gets a chance to be passed to Println.

The end value is not printed because as soon as the main goroutine (the main function is actually a goroutine) is finished (in other terms get unblocked) the other non-main goroutines does not have the chance to get completed.

When the function main() returns, the program exits. Moreover goroutines are independent units of execution and when a number of them starts one after the other you cannot depend on when a goroutine will actually be started. The logic of your code must be independent of the order in which goroutines are invoked.

One way to solve your problem (and the easiest one in your case) is to put a time.Sleep at the end of your main() function.

time.Sleep(1e9)

This will guarantee that the main goroutine will not unblock and the other goroutines will have a change to get executed.

package main

import (
    "fmt"
    "time"
)

func main() {
    start := make(chan int)
    end := make(chan int)

    go func() {
        fmt.Println("Start")
        fmt.Println(<-start)
    }()

    go func() {
        fmt.Println("End")
        fmt.Println(<-end)
    }()

    start <- 1
    end <- 2

    time.Sleep(1e9)
}

Another solution as you mentioned is to use waitgroup.

Apart from sleep where you have to specify the time, you can use waitgroup to make you program wait until the goroutine completes execution.

package main

import "fmt"
import "sync"

var wg sync.WaitGroup

func main() {
    start := make(chan int)
    end := make(chan int)

    wg.Add(2)
    go func() {
        defer wg.Done()
        fmt.Println("Start")
        fmt.Println(<-start)
    }()

    go func() {
        defer wg.Done()
        fmt.Println("End")
        fmt.Println(<-end)
    }()

    start <- 1
    end <- 2
    wg.Wait()
}