2013-08-22 24 views
9

Gitmek için yeni ve eşzamanlılık ve kanal anlama konusunda bir sorun yaşıyorum.Eşzamanlılık ve kanal karışıklığı git

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 
} 

Programın çıktısı:

display first message: hello 
10000000000 

Ama yalnızca bir satır olmalıdır düşündü:

display first message: hello 

Yani ana işlevi, < -c bu engelleme olduğunu ve diğer iki kanalın da veriyi kanala göndermesini bekler. Ana işlev c'den veri aldığında, devam etmeli ve çıkmalıdır.

ekran ve toplamı aynı anda çalıştırın ve toplamı c sadık göndermesi gerektiğini artık o kadar ekran alır ve toplamı bitirir önce program ben açıkça anlamak emin değilim

... çıkmalısınız. Biri bunun için yardımcı olabilir mi? Teşekkür ederim!

+0

Tux21b'nin önerdiği gibi, muhtemelen 'runtime.GOMAXPROCS' nedeniyle. Yumrukla, bir fark görebiliyorsun. – dyoo

cevap

4

Programınızın tam çıkışı tanımlanmamıştır ve zamanlayıcıya bağlıdır. Zamanlayıcı, şu anda engellenmeyen tüm goroutinler arasında serbestçe seçim yapabilir. Mevcut goroutini çok kısa zaman aralıklarında değiştirerek aynı anda bu goroutines'i çalıştırmaya çalışır, böylece kullanıcı her şeyin simultane bir şekilde gerçekleştiğini hisseder. Buna ek olarak, aynı zamanda farklı CPU'larda (birden çok sisteme sahipseniz ve runtime.GOMAXPROCS'u arttırırsanız) birden fazla goroutini çalıştırabilirsiniz. çıktınıza yol açabilecek bir durumdur:

  1. main iki goroutines
  2. zamanlayıcısı hemen yeni goroutines birine geçmek için seçtiği oluşturur ve mesajın dışarı display
  3. display baskılar seçer ve tarafından engellenen Henüz bir alıcı olmadığından kanal (c <- true) gönderir.
  4. zamanlayıcı çalıştırmak için seçtiği sum sonraki
  5. toplamı ekranda hesaplanır ve basılır
  6. zamanlayıcı sum goroutine (zaten zaman adil bir miktar kullandı) sürdüremez seçer ve display
  7. ile devam
  8. display kanal
  9. zamanlayıcı sonraki ana
  10. ana başabaş çalıştırmak için tercih
  11. ve goroutines yok edilir değerini gönderir

Ancak bu sadece olası bir yürütme sırasıdır. Pek çokları var ve bazıları da farklı bir çıktıya yol açacak. Sadece ilk sonucu yazdırmak ve sonradan programı bırakmak istiyorsanız,kullanın ve main işlevinizi fmt.Println(<-result) yazdırabilirsiniz.

+0

Açıklama için teşekkürler. 3. adımda, bir alıcı olmadığından ekran, kanal gönderimiyle engellenir. Eh ... Alıcı ne zaman hazır? – SteelwingsJZ

+1

Kanal senkrondır, yani hem alıcı hem de gönderenin değeri iletmek için hazır olması gerektiği anlamına gelir.Eğer bir goroutine ilk önce c <- true' yürütülürse, başka bir goroutine <-c' çalıştırılıncaya kadar engellenecektir. Ama aynı zamanda başka bir goroutine 'cc' eşleşmesi olana kadar <-c' icra eden bir goroutinin engellenmesi de mümkündür. – tux21b

+0

Sadece bir yorum. Bildiğim kadarıyla, mevcut sürümdeki Git zamanlayıcısı önleyici değildir. Bir goroutine CPU'ya sahip olduğunda, bloke edilene kadar (I/O, kanal, muteks vb.) Başka bir tanesine geçmeyecektir. Yani, eğer ilk önce idam yapılırsa, sadece kanal tarafından engellenene kadar CPU kullanacaktır (fmt.Println'in bir CPU anahtarı üretip üretemeyeceğinden emin değilim). Go 1.2 için bir önleyici zamanlayıcı planlandı, okurum. Tabii ki, eğer GOMAXPROCS 1 değilse, diğer goroutine başka bir SO-level işlemi kullanacak ve SO tarafından planlanacaktır. Daha fazla bilgi burada: http://dominik.honnef.co/go-tip/2013-08-15/ – siritinga