2013-08-22 8 views
9

Jestem nowym użytkownikiem Go i mam problem ze zrozumieniem współbieżności i kanału.Go współbieżność i zamieszanie kanału

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 
} 

Wyjście programu jest:

display first message: hello 
10000000000 

Ale myślałem, powinno być tylko jedna linia:

display first message: hello 

więc w głównej funkcji < -c blokuje go i czeka, aż pozostałe dwa przejdą rountines do wysłania danych do kanału. Gdy główna funkcja odbiera dane z c, powinna kontynuować i wyjść.

wyświetlacz i uruchomić jednocześnie suma i suma trwa dłużej tak Wyświetlacz powinien wysłać prawdziwe C, a program powinien zakończyć zanim zakończy suma ...

Nie jestem pewien, czy rozumiem go wyraźnie. Czy ktoś może mi w tym pomóc? Dziękuję Ci!

+0

Zgodnie z sugestią tux21b, jest to prawdopodobnie spowodowane 'runtime.GOMAXPROCS'. Podbij to i możesz zauważyć różnicę. – dyoo

Odpowiedz

4

Dokładne dane wyjściowe programu nie są zdefiniowane i zależą od programu planującego. Harmonogram może swobodnie wybierać między wszystkimi goroutinami, które nie są obecnie zablokowane. Próbuje uruchomić te goryle jednocześnie, przełączając obecny goroutine w bardzo krótkich odstępach czasu, tak aby użytkownik czuł, że wszystko dzieje się jednocześnie. Oprócz tego może on również wykonywać więcej niż jedną goroutine równolegle na różnych procesorach (jeśli masz system wielordzeniowy i zwiększysz runtime.GOMAXPROCS). Jedna sytuacja, która może doprowadzić do wyjścia jest:

  1. main tworzy dwa goroutines
  2. planista wybiera, aby przejść do jednego z nowych goroutines natychmiast i wybiera display
  3. display wypisuje wiadomości i jest blokowany przez kanał wysyła (c <- true), ponieważ nie ma jeszcze odbiornika.
  4. planista wybiera uruchomić sum obok
  5. suma jest obliczana i drukowane na ekranie
  6. planista wybiera nie wznowić sum goroutine (ma już używany sporo czasu) i kontynuuje display
  7. display wysyła wartość do kanału
  8. planista wybiera uruchomić główne kolejne
  9. główne zostanie zamknięty, a wszystkie goroutines są zniszczone

Ale to tylko jedna z możliwych kolejności wykonania. Jest wiele innych, a niektóre z nich doprowadzą do innej wydajności. Jeśli chcesz wydrukować tylko pierwszy wynik i później zakończyć program, prawdopodobnie powinieneś użyć result chan string i zmienić swoją funkcję main, aby wydrukować fmt.Println(<-result).

+0

Dzięki za wyjaśnienia. W kroku 3 wyświetlanie jest blokowane przez kanał wysyłany, ponieważ nie ma odbiornika. Eh ... Kiedy odbiornik jest gotowy? – SteelwingsJZ

+1

Kanał jest synchroniczny, co oznacza, że ​​zarówno odbiorca, jak i nadawca muszą być gotowi do przesłania wartości.Jeśli goroutine najpierw wykona 'c <- true', zostanie zablokowany, dopóki inna goroutine nie wykona' <-c'. Ale jest też możliwe, że goroutine, który wykonuje '<-c', jest blokowany, dopóki nie znajdzie pasującego' c <- true' w innej goroutine. – tux21b

+0

Tylko komentarz. O ile mi wiadomo, harmonogram Go w obecnej wersji nie jest zapobiegawczy. Gdy goroutin ma procesor, nie przejdzie na inny, dopóki nie zostanie zablokowany (z powodu I/O, kanału, muteksu itp.). Więc jeśli suma zostanie wykonana jako pierwsza, będzie używać procesora wyłącznie do momentu zablokowania przez kanał (nie jestem pewien, czy fmt.Println może wytworzyć przełącznik CPU). Planowanie prewencyjne jest planowane dla Go 1.2, czytałem. Oczywiście, jeśli GOMAXPROCS nie jest równy 1, inna goryntyna użyje innego procesu na poziomie SO i zostanie zaplanowana przez SO. Więcej informacji tutaj: http://dominik.honnef.co/go-tip/2013-08-15/ – siritinga