goroutines 的执行顺序

goroutines order of execution

我正在尝试理解这段代码,不确定为什么第二次执行在第一次执行之前。如果有人真的能帮我解决这个问题就太好了!

func sum(a []int, c chan int) {
   fmt.Println("summing: ", a)
   total := 0
   for _, v := range a {
      total += v
   }
   //fmt.Println("send to c",total)
   c <- total  // send total to c
}
func main() {
    //a := []int{7, 2, 8,134,23,23,1,23,1234,143, -9, 4, 0, 1234}

    c := make(chan int)

    go sum([]int{1,2,3}, c)
    go sum([]int{4,5,6}, c)

    x := <-c
    fmt.Println(x)
    x = <-c
    fmt.Println(x)
}

输出:

summing:  [4 5 6]
15
summing:  [1 2 3]
6

您没有明确同步两个 goroutine 的顺序。如果您 运行 的次数足够多,您将看到对 fmt.Println 的调用以不同的顺序打印。当执行 goroutines 时,因为它们是并发操作,你无法保证它们何时会执行 and/or 完成。您需要使用各种标准库包或通道本身来同步并发 运行ning goroutines 的执行。

例如(通过利用通道的阻塞特性,您可以做类似的事情):

func main() {

    c := make(chan int)

    go sum([]int{1, 2, 3}, c)

    //use the channel to block until it receives a send
    x := <-c
    fmt.Println(x)

    //then execute the next routine
    go sum([]int{4, 5, 6}, c)

    x = <-c
    fmt.Println(x)
}

另一个例子(不太实用,但这里是为了看看其他常见的 go 同步功能)你可以引入一个等待组,以及一个通道上的范围:

func sum(a []int, c chan int, wg *sync.WaitGroup) {
    defer wg.Done()
    fmt.Println("summing: ", a)
    total := 0
    for _, v := range a {
        total += v
    }
    //fmt.Println("send to c",total)
    c <- total // send total to c
}

func main() {

    c := make(chan int)
    wg := new(sync.WaitGroup)

    //concurrently call the concurrent calls to sum, allowing execution to continue to the range of the channel 
    go func() {
        //increment the wait group, and pass it to the sum func to decrement it when it is complete
        wg.Add(1)
        go sum([]int{1, 2, 3}, c, wg)
        //wait for the above call to sum to complete
        wg.Wait()
        //and repeat...
        wg.Add(1)
        go sum([]int{4, 5, 6}, c, wg)
        wg.Wait()
        //all calls are complete, close the channel to allow the program to exit cleanly 
        close(c)
    }()

    //range of the channel
    for theSum := range c {
        x := theSum
        fmt.Println(x)
    }

}