为什么这里有通道可变输出

I am trying code modified from here. I create 5 channels and send data 5 times:

package main
import "fmt"
func greet(c chan string) {
    fmt.Println("Hello " + <-c + "!")
}
func main() {
    fmt.Println("main() started")
    c := make(chan string)
    for i:=0; i<5; i++ {
        go greet(c)
    }
    c <- "AAA"
    c <- "BBB"
    c <- "CCC"
    c <- "DDD"
    c <- "EEE"
    fmt.Println("main() stopped")
}

I expected all 5 strings to be printed. However, I find variable output. Some outputs are:

$ ./rnchannel
main() started
Hello AAA!
Hello DDD!
Hello BBB!
Hello CCC!
Hello EEE!
main() stopped

$ ./rnchannel
main() started
Hello CCC!
Hello DDD!
main() stopped

$ ./rnchannel
main() started
Hello CCC!
Hello BBB!
Hello AAA!
Hello DDD!
main() stopped

Why variable number of lines are being printed?

@AdamSmith identified the problem. When main() exits all goroutines are killed. There's no guarantee your other goroutines will finish before that, that's the nature of concurrency. Here's how you fix it.

First, let's make a couple changes to greet. Have it sleep just a moment to make the problem more pronounced. We'll also have it accept a string rather than the channel, we'll see why in a moment.

func greet(str string) {
    time.Sleep(100 * time.Millisecond)
    fmt.Println("Hello " + str + "!")
}

Rather than creating a bunch of goroutines to read a fixed number of times from a channel, we want one goroutine which reads from the channel until it's exhausted. This is easiest done using range. This takes full advantage of channels.

We also need a way to tell the main program to wait until the loop is done. This is easiest done with a second channel. More complex synchronization uses WaitGroups.

c := make(chan string, 2)
done := make(chan bool, 1)
go func() {
    for str := range(c) {
        greet(str)
    }
    done <- true
}()

The goroutine will read from c until it's closed. Then it will send true to the channel done. Both are buffered to avoid deadlock due to blocking waiting to read or write to the channel.

Back in main, we write to the channel, explicitly close it, and then wait to read from done.

    c <- "AAA"
    c <- "BBB"
    c <- "CCC"
    c <- "DDD"
    c <- "EEE"
    close(c)

    <-done
    fmt.Println("main() stopped")

<-done will block until there is something to read. This allows the goroutine to finish.

And bringing it all together.

package main
import(
    "fmt"
    "time"
)
func greet(str string) {
    time.Sleep(100 * time.Millisecond)
    fmt.Println("Hello " + str + "!")
}
func main() {
    fmt.Println("main() started")
    c := make(chan string, 2)
    done := make(chan bool, 1)
    go func() {
        for str := range(c) {
            greet(str)
        }
        done <- true
    }()
    c <- "AAA"
    c <- "BBB"
    c <- "CCC"
    c <- "DDD"
    c <- "EEE"
    close(c)

    <-done
    fmt.Println("main() stopped")
}

You're not waiting until all strings are printed to exit. As soon as the main thread reaches its end of execution, it shuts down all goroutines and ends the program. Since this happens concurrently, it's impossible to say how many strings will be allowed to print.