Golang channels, order of execution

亡梦爱人 提交于 2019-12-11 03:34:00

问题


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?


回答1:


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.




回答2:


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\n", name)
    time.Sleep(time.Second * time.Duration(sleep))

    sum := 0

    for _, v := range a { 
        sum += v
    }   
    fmt.Printf("about end goroutine: %s\n", 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



回答3:


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.



来源:https://stackoverflow.com/questions/51996941/golang-channels-order-of-execution

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!