Golang频道,执行顺序

I'm learning Go, and have run across the following code snippet:

package main

import "fmt"

func sum(a []int, c chan int) {
    sum := 0
    for _, v := range a {
        sum += v
    }
    c <- sum // send sum to c
}

func main() {
    a := []int{7, 2, 8, -9, 4, 0}

    c := make(chan int, 2)
    go sum(a[0:3], c)
    go sum(a[3:6], c)
    x := <-c
    y := <-c
    // x, y := <-c, <-c // receive from c

    fmt.Println(x, y)
}

Output:

-5 17

Program exited.

Can someone please tell me why the 2nd calling of the "sum" function is coming through the channel before the 1st one? It seems to me that the output should be:

17 -5

I've also tested this with an un-buffered channel and it also gives the same order of output. What am I missing?

You are calling the go routine in your code and you can't tell when the routine will end and the value will be passed to the buffered channel.

As this code is asynchronous so whenever the routine will finish it will write the data to the channel and will be read on the other side. In the example above you are calling only two go routines so the behavior is certain and same output is generated somehow for most of the cases but when you will increase the go routines the output will not be same and the order will be different unless you make it synchronous.

Example:

package main

import "fmt"

func sum(a []int, c chan int) {
    sum := 0
    for _, v := range a {
        sum += v
    }
    c <- sum // send sum to c
}

func main() {
    a := []int{7, 2, 8, -9, 4, 2, 4, 2, 8, 2, 7, 2, 99, -32, 2, 12, 32, 44, 11, 63}

    c := make(chan int)
    for i := 0; i < len(a); i = i + 5 {
        go sum(a[i:i+5], c)
    }
    output := make([]int, 5)
    for i := 0; i < 4; i++ {
        output[i] = <-c
    }
    close(c)

    fmt.Println(output)
}

The output for this code on different sample runs was

[12 18 0 78 162] 

[162 78 12 0 18]

[12 18 78 162 0]

This is because the goroutines wrote the output asynchronously to the buffered channel.

Hope this helps.

Goroutines are started asynchronously and they can write to channel in any order. It is easier to see if you modify your example a little bit:

package main

import (
    "fmt"
    "time"
)

func sum(a []int, c chan int, name string, sleep int) {
    fmt.Printf("started goroutine: %s
", name)
    time.Sleep(time.Second * time.Duration(sleep))

    sum := 0

    for _, v := range a { 
        sum += v
    }   
    fmt.Printf("about end goroutine: %s
", name)
    c <- sum // send sum to c
}

func main() {
    a := []int{7, 2, 8, -9, 4, 0}

    c := make(chan int, 2)
    go sum(a[0:3], c, "A", 1)
    go sum(a[3:6], c, "B", 1)
    x := <-c 
    y := <-c 
    // x, y := <-c, <-c // receive from c

    fmt.Println(x, y)
}

https://play.golang.org/p/dK4DT0iUfzY

Result:

started goroutine: B
started goroutine: A
about end goroutine: A
about end goroutine: B
17 -5

When running the golang.org sandbox, I got the same result every time. As stated above. But when I ran the same snippet on in my own sandbox (on my computer), it sometimes changed the order of the threads. This is much more satisfactory. It shows I can't expect any particular order to thread execution, which is intuitive. I just couldn't figure out why I was getting the same order of execution, and it was the reverse of the order the threads were started. I think this was just luck of the draw on the golang.org's sandbox.