Перейти к параллелизму и путанице в каналах

Я новичок в Go, и у меня проблемы с пониманием параллелизма и канала.

package main

import "fmt"

func display(msg string, c chan bool){
    fmt.Println("display first message:", msg)
    c <- true
}

func sum(c chan bool){
    sum := 0
    for i:=0; i < 10000000000; i++ {
        sum++
    }
    fmt.Println(sum)
    c <- true
}

func main(){
    c := make(chan bool)

    go display("hello", c)
    go sum(c)
    <-c
}

Результат программы:

display first message: hello
10000000000 

Но я подумал, что это должна быть только одна строка:

display first message: hello

Итак, в основной функции ‹-c блокирует ее и ожидает, пока два других не перейдут к отправке данных в канал. Как только основная функция получит данные от c, она должна продолжить и выйти.

отображение и сумма запускаются одновременно, и сумма занимает больше времени, поэтому display должен отправить true в c, и программа должна выйти до завершения суммы ...

Я не уверен, что понимаю это ясно. Может ли кто-нибудь помочь мне с этим? Спасибо!


person Community    schedule 22.08.2013    source источник
comment
Как предполагает tux21b, это, вероятно, из-за runtime.GOMAXPROCS. Поднимите его, и вы увидите разницу.   -  person dyoo    schedule 23.08.2013


Ответы (1)


Точный вывод вашей программы не определен и зависит от планировщика. Планировщик может свободно выбирать между всеми горутинами, которые в настоящее время не заблокированы. Он пытается запускать эти горутины одновременно, переключая текущую горутину за очень короткие промежутки времени, чтобы у пользователя возникло ощущение, что все происходит одновременно. В дополнение к этому, он также может выполнять более одной горутины параллельно на разных процессорах (если у вас многоядерная система и увеличьте runtime.GOMAXPROCS). Одна ситуация, которая может привести к вашему выводу:

  1. main создает две горутины
  2. планировщик решает немедленно переключиться на одну из новых горутин и выбирает display
  3. display распечатывает сообщение и блокируется каналом отправки (c <- true), так как получателя еще нет.
  4. планировщик выбирает запуск sum следующим
  5. сумма вычисляется и выводится на экран
  6. планировщик решает не возобновлять sum горутину (она уже использовала изрядное количество времени) и продолжает display
  7. display отправляет значение в канал
  8. планировщик выбирает запуск основного следующего
  9. основные выходы и все горутины уничтожаются

Но это лишь один из возможных порядков исполнения. Есть много других, и некоторые из них приведут к другому результату. Если вы хотите напечатать только первый результат и затем выйти из программы, вам, вероятно, следует использовать result chan string и изменить функцию main на печать fmt.Println(<-result).

person tux21b    schedule 22.08.2013
comment
Спасибо за разъяснения. На шаге 3 отображение блокируется отправкой канала, так как нет получателя. Эх ... Когда будет готов ресивер? - person ; 23.08.2013
comment
Канал является синхронным, что означает, что и получатель, и отправитель должны быть готовы к передаче значения. Если горутина сначала выполняется c <- true, она будет заблокирована до тех пор, пока другая горутина не выполнит <-c. Но также возможно, что горутина, выполняющая <-c, будет заблокирована до тех пор, пока не будет найдено совпадение c <- true в другой горутине. - person tux21b; 23.08.2013
comment
Просто комментарий. Насколько мне известно, планировщик Go в текущей версии не является вытесняющим. Как только у горутины есть ЦП, она не переключится на другую, пока не будет заблокирована (из-за ввода-вывода, канала, мьютекса и т. Д.). Поэтому, если сначала выполняется sum, он будет использовать ЦП исключительно до тех пор, пока канал не будет заблокирован (я не уверен, может ли fmt.Println вызвать переключение ЦП). Я читал, что в Go 1.2 планируется вытесняющий планировщик. Конечно, если GOMAXPROCS не 1, другая горутина будет использовать другой процесс уровня SO и будет запланирована SO. Дополнительная информация здесь: dominik.honnef.co/go-tip/2013-08 -15 - person siritinga; 27.08.2013