2013-08-22 7 views
9

मैं जाने के लिए नया हूं और समवर्ती और चैनल को समझने में समस्या है।जाओ समवर्ती और चैनल भ्रम

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 रोक रहा है और चैनल को डेटा भेजने के लिए अन्य दो राउंटीन जाने की प्रतीक्षा करता है। एक बार मुख्य समारोह सी से डेटा प्राप्त करने के बाद, इसे आगे बढ़ना चाहिए और बाहर निकलना चाहिए।

प्रदर्शन और योग एक साथ चलाने के लिए और राशि अब ग के लिए इतना प्रदर्शन लेता है सच भेजना चाहिए और इस कार्यक्रम से बाहर निकलने से पहले योग खत्म ...

मुझे यकीन है कि मैं यह स्पष्ट रूप से समझ में नहीं हूँ। क्या कोई इस से मेरी मदद कर सकता है? धन्यवाद!

+0

जैसा कि tux21b सुझाव देता है, यह शायद 'runtime.GOMAXPROCS' के कारण है। इसे टक्कर लगी, और आप एक अंतर देख सकते हैं। स्पष्टीकरण के लिए – dyoo

उत्तर

4

आपके प्रोग्राम का सटीक आउटपुट परिभाषित नहीं किया गया है और शेड्यूलर पर निर्भर करता है। शेड्यूलर वर्तमान में अवरुद्ध नहीं होने वाले सभी गोरोटाइन के बीच स्वतंत्र रूप से चुन सकता है। यह वर्तमान goroutine को बहुत कम समय अंतराल में स्विच करके उन goroutines को एक साथ चलाने की कोशिश करता है ताकि उपयोगकर्ता को यह महसूस हो जाए कि सबकुछ एक साथ होता है। इसके अलावा, यह विभिन्न CPUs पर समानांतर में एक से अधिक गोरौटाइन भी निष्पादित कर सकता है (यदि आपके पास मल्टीकोर सिस्टम होता है और runtime.GOMAXPROCS बढ़ता है)। एक स्थिति है कि अपने उत्पादन को जन्म दे सकता है:

  1. main दो goroutines
  2. अनुसूचक तुरंत नए goroutines में से एक करने के लिए स्विच करने के लिए चुनता बनाता है और संदेश बाहर display
  3. display प्रिंट चुनता है और द्वारा अवरुद्ध है चैनल भेजता है (c <- true) क्योंकि अभी तक कोई रिसीवर नहीं है।
  4. अनुसूचक चलाने का निर्णय लेता sum अगले
  5. राशि की गणना की और स्क्रीन पर छपा है
  6. अनुसूचक sum goroutine (यह पहले से ही समय भी पर्याप्त मात्रा में इस्तेमाल किया गया है) फिर से शुरू नहीं करने के लिए चुनता है और display
  7. के साथ जारी है
  8. display चैनल
  9. अनुसूचक मुख्य अगले
  10. मुख्य इस्तीफा चलाने का निर्णय लेता है और सभी goroutines नष्ट कर रहे हैं के लिए मूल्य भेजता

लेकिन यह केवल एक संभावित निष्पादन आदेश है। कई अन्य हैं और उनमें से कुछ एक अलग उत्पादन के लिए नेतृत्व करेंगे। यदि आप केवल पहले परिणाम मुद्रित करना चाहते हैं और बाद में कार्यक्रम छोड़ना चाहते हैं, तो आपको शायद result chan string का उपयोग करना चाहिए और फ़ंक्शन को fmt.Println(<-result) प्रिंट करने के लिए बदलें।

+0

धन्यवाद। चरण 3 में, चैनल द्वारा प्रेषित किया गया है क्योंकि प्रेषक एक रिसीवर नहीं है। एह ... रिसीवर कब तैयार है? – SteelwingsJZ

+1

चैनल तुल्यकालिक है जिसका अर्थ है कि दोनों, रिसीवर और प्रेषक मूल्य संचारित करने के लिए तैयार होना चाहिए।यदि कोई गोरौटाइन पहले 'c <- true' निष्पादित करता है, तो इसे तब तक अवरुद्ध कर दिया जाएगा जब तक कि कोई अन्य गोरौटाइन '<-c' निष्पादित न हो जाए। लेकिन यह भी संभव है कि एक goroutine जो '<-c' निष्पादित करता है तब तक अवरुद्ध हो जाता है जब तक कि कोई अन्य goroutine में मिलान' c <- true' न हो। – tux21b

+0

बस एक टिप्पणी। जहां तक ​​मुझे पता है, वर्तमान संस्करण में गो शेड्यूलर प्रीemptive नहीं है। एक बार goroutine सीपीयू होने के बाद, यह अवरुद्ध होने तक किसी अन्य पर स्विच नहीं करेगा (I/O, चैनल, म्यूटेक्स, आदि के कारण)। तो अगर राशि पहले निष्पादित की जाती है, तो यह चैनल द्वारा अवरुद्ध होने तक विशेष रूप से सीपीयू का उपयोग करेगी (मुझे यकीन नहीं है कि fmt.Println एक CPU स्विच उत्पन्न कर सकता है)। गो 1.2 के लिए प्रीपेप्टिव शेड्यूलर की योजना बनाई गई है, मैंने पढ़ा है। बेशक, यदि GOMAXPROCS 1 नहीं है, तो अन्य goroutine एक और एसओ-स्तरीय प्रक्रिया का उपयोग करेगा और एसओ द्वारा निर्धारित किया जाएगा। यहां अधिक जानकारी: http://dominik.honnef.co/go-tip/2013-08-15/ – siritinga

संबंधित मुद्दे