порядок выполнения программы

#go #goroutine

#Вперед #goroutine

Вопрос:

Я пытаюсь понять этот фрагмент кода, не уверен, почему 2-й запуск выполняется перед 1-м. Было бы здорово, если бы кто-нибудь действительно мог мне в этом помочь!

 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
  

Ответ №1:

У вас нет ничего явно синхронизирующего порядок двух программ. Если вы запустите это достаточно много раз, вы увидите вызовы для fmt.Println печати в разных последовательностях. При выполнении процедур, поскольку они являются параллельными операциями, у вас нет никаких гарантий, когда они будут выполнены и / или завершены. Вам необходимо использовать различные пакеты стандартных библиотек или сами каналы для синхронизации выполнения одновременно запущенных программ.

Например (используя блокирующий характер каналов, вы могли бы сделать что-то вроде):

 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)
    }

}