वास्तव में रनटाइम क्या है।


86

में एक संस्करण जाओ की यात्रा वेबसाइट के चलते 1.5 के जारी होने से पहले , वहाँ कोड का एक टुकड़ा है कि इस तरह दिखता है।

package main

import (
    "fmt"
    "runtime"
)

func say(s string) {
    for i := 0; i < 5; i++ {
        runtime.Gosched()
        fmt.Println(s)
    }
}

func main() {
    go say("world")
    say("hello")
}

आउटपुट इस तरह दिखता है:

hello
world
hello
world
hello
world
hello
world
hello

जो मुझे परेशान कर रहा है वह यह है कि जब runtime.Gosched()हटा दिया जाता है, तो कार्यक्रम अब "दुनिया" प्रिंट नहीं करता है।

hello
hello
hello
hello
hello

ऐसा क्यों हैं? runtime.Gosched()निष्पादन को कैसे प्रभावित करता है ?

जवाबों:


143

ध्यान दें:

गो 1.5 के रूप में, GOMAXPROCS हार्डवेयर के कोर की संख्या पर सेट है: golang.org/doc/go1.5#runtime , मूल उत्तर 1.5 से नीचे।


जब आप GOMAXPROCS पर्यावरण चर को निर्दिष्ट किए बिना गो कार्यक्रम चलाते हैं, तो गो OSoutines एकल OS थ्रेड में निष्पादन के लिए निर्धारित है। हालाँकि, प्रोग्राम बनाने के लिए मल्टीथ्रेडेड दिखाई देते हैं (जो कि गोरोइटिन हैं, वे नहीं हैं?), गो शेड्यूलर को कभी-कभी निष्पादन के संदर्भ को बंद करना होगा, इसलिए प्रत्येक गोरआउट अपना काम कर सकता है।

जैसा कि मैंने कहा, जब GOMAXPROCS चर निर्दिष्ट नहीं किया जाता है, तो गो रनटाइम को केवल एक थ्रेड का उपयोग करने की अनुमति है, इसलिए निष्पादन के संदर्भों को स्विच करना असंभव है, जबकि गोरूटीन कुछ पारंपरिक काम कर रहा है, जैसे संगणना या यहां तक ​​कि आईओ (जो सादे सी कार्यों के लिए मैप किया गया है) )। संदर्भ को तभी स्विच किया जा सकता है जब गो कंसिस्टेंसी प्राइमेटिव का उपयोग किया जाता है, उदाहरण के लिए जब आप कई मंत्रों पर स्विच करते हैं, या (यह आपका मामला है) जब आप संदर्भदाताओं को संदर्भों को स्विच करने के लिए स्पष्ट रूप से बताते हैं - यह वही है जो runtime.Goschedहै।

इसलिए, संक्षेप में, जब एक गोरेइन में निष्पादन संदर्भ Goschedकॉल पर पहुंच जाता है , तो अनुसूचक को निर्देश को दूसरे गाउटआउट में बदलने का निर्देश दिया जाता है। आपके मामले में दो गोरोनाइट हैं, मुख्य (जो कि कार्यक्रम के 'मुख्य' धागे का प्रतिनिधित्व करता है) और अतिरिक्त, एक जिसे आपने बनाया है go say। यदि आप Goschedकॉल हटाते हैं, तो निष्पादन संदर्भ को पहले गोरोइन से दूसरे में स्थानांतरित नहीं किया जाएगा, इसलिए आपके लिए कोई 'दुनिया' नहीं है। जब Goschedउपस्थित होता है, तो शेड्यूलर प्रत्येक लूप पुनरावृत्ति पर पहले गोरोइन से दूसरे और इसके विपरीत पर निष्पादन को स्थानांतरित करता है, इसलिए आपके पास 'हैलो' और 'वर्ल्ड' इंटरलेय्ड है।

FYI करें, इसे 'कोऑपरेटिव मल्टीटास्किंग' कहा जाता है: गोरोइन्ट्स को अन्य गोरआउट्स के लिए स्पष्ट रूप से नियंत्रण प्राप्त करना चाहिए। अधिकांश समकालीन OS में उपयोग किए जाने वाले दृष्टिकोण को 'प्रीमेप्टिव मल्टीटास्किंग' कहा जाता है: निष्पादन थ्रेड्स नियंत्रण हस्तांतरण के साथ संबंधित नहीं हैं; शेड्यूलर निष्पादन निष्पादन संदर्भों को पारदर्शी रूप से उनके बजाय बदल देता है। सहकारी दृष्टिकोण अक्सर 'ग्रीन थ्रेड्स' को लागू करने के लिए उपयोग किया जाता है, अर्थात्, तार्किक समवर्ती कोरआउट जो ओएस थ्रेड्स 1: 1 से मैप नहीं करते हैं - यह है कि गो रनटाइम और इसके गोरआउट्स को कैसे लागू किया जाता है।

अपडेट करें

मैंने GOMAXPROCS पर्यावरण चर का उल्लेख किया है, लेकिन यह क्या है, इसकी व्याख्या नहीं की। इसे ठीक करने का समय आ गया है।

जब यह चर एक सकारात्मक संख्या में सेट हो जाता है N, तो गो रनटाइम Nदेशी थ्रेड्स बनाने में सक्षम होगा , जिस पर सभी हरे रंग के धागे निर्धारित होंगे। मूल धागा एक प्रकार का धागा है जो ऑपरेटिंग सिस्टम (विंडोज थ्रेड्स, pthreads आदि) द्वारा बनाया गया है। इसका मतलब है कि यदि N1 से अधिक है, तो यह संभव है कि गोरोइटिन को अलग-अलग मूल थ्रेड्स में निष्पादित करने के लिए निर्धारित किया जाएगा और, परिणामस्वरूप, समानांतर (कम से कम, आपके कंप्यूटर की क्षमताओं तक) में चलाया जाएगा: यदि आपका सिस्टम मल्टीकोर प्रोसेसर पर आधारित है, तो यह संभावना है कि ये धागे वास्तव में समानांतर होंगे; यदि आपके प्रोसेसर में सिंगल कोर है, तो ओएस थ्रेड्स में कार्यान्वित प्रीमेप्टिव मल्टीटास्किंग समानांतर निष्पादन की दृश्यता बनाएगा)।

runtime.GOMAXPROCS()पर्यावरण चर को पूर्व-निर्धारित करने के बजाय फ़ंक्शन का उपयोग करके GOMAXPROCS चर सेट करना संभव है । करंट के बजाय अपने प्रोग्राम में कुछ इस तरह का प्रयोग करें main:

func main() {
    runtime.GOMAXPROCS(2)
    go say("world")
    say("hello")
}

इस मामले में आप दिलचस्प परिणाम देख सकते हैं। यह संभव है कि आपको असमान रूप से मुद्रित interleaved 'हैलो' और 'दुनिया' लाइनें मिलेंगी, जैसे

hello
hello
world
hello
world
world
...

यह हो सकता है अगर गोरोनाइट को ओएस थ्रेड्स को अलग करने के लिए निर्धारित किया जाए। यह वास्तव में है कि प्रीमेप्टिव मल्टीटास्किंग कैसे काम करता है (या मल्टीकोर सिस्टम के मामले में समानांतर प्रसंस्करण): थ्रेड्स समानांतर होते हैं, और उनका संयुक्त उत्पादन अनिश्चितकालीन होता है। BTW, आप Goschedकॉल को छोड़ या हटा सकते हैं, ऐसा लगता है कि जब GOMAXPROCS 1 से बड़ा है तो इसका कोई प्रभाव नहीं होगा।

निम्नलिखित है जो मुझे runtime.GOMAXPROCSकॉल के साथ कार्यक्रम के कई रनों पर मिला ।

hyperplex /tmp % go run test.go
hello
hello
hello
world
hello
world
hello
world
hyperplex /tmp % go run test.go
hello
world
hello
world
hello
world
hello
world
hello
world
hyperplex /tmp % go run test.go
hello
hello
hello
hello
hello
hyperplex /tmp % go run test.go
hello
world
hello
world
hello
world
hello
world
hello
world

देखें, कभी-कभी आउटपुट बहुत सुंदर होता है, कभी-कभी नहीं। कार्रवाई में अनिश्चिततावाद :)

एक और अपडेट

ऐसा लगता है कि गो संकलक के नए संस्करणों में गो रनटाइम गोरोइटिन को केवल संगामिति आदिम उपयोग पर नहीं बल्कि ओएस सिस्टम कॉल पर भी उपज देता है। इसका मतलब है कि निष्पादन संदर्भ को गोरों के बीच भी IO फ़ंक्शन कॉल पर स्विच किया जा सकता है। नतीजतन, हाल के गो संकलक में यह संभव है कि जब GOMAXPROCS परेशान हो या 1 पर सेट हो, तब भी अनिश्चितकालीन व्यवहार का निरीक्षण किया जा सकता है।


अच्छा काम ! लेकिन मैंने इस मुद्दे को 1.0.3, अजीब के तहत पूरा नहीं किया।
वूहोआ

1
यह सच है। मैंने इसे केवल 1.0.3 के साथ जांचा, और हां, यह व्यवहार प्रकट नहीं हुआ: यहां तक ​​कि GOMAXPROCS == 1 के साथ भी इस कार्यक्रम में काम किया जैसे कि GOMAXPROCS> = 2. लगता है कि 1.0.3 में शेड्यूलर को ट्विक किया गया है।
व्लादिमीर मतावेव

मुझे लगता है कि चीजें बदल गई हैं 1.4 गो संकलक। OPs प्रश्न में उदाहरण OS थ्रेड बनाते हुए प्रतीत होता है, जबकि यह (-> gobyexample.com/atomic-counters ) सहकारी समय-निर्धारण बनाने के लिए लगता है। कृपया जवाब अपडेट करें यदि यह सच है
Tez

8
गो 1.5 के रूप में, GOMAXPROCS हार्डवेयर के कोर की संख्या पर सेट है: golang.org/doc/go1.5#runtime
apanuto

1
@paulkon, Gosched()की आवश्यकता है या नहीं यह आपके कार्यक्रम पर निर्भर करता है, यह GOMAXPROCSमूल्य पर निर्भर नहीं करता है । सहकारी एक पर प्रीमेप्टिव मल्टीटास्किंग की दक्षता भी आपके कार्यक्रम पर निर्भर करती है। यदि आपका प्रोग्राम I / O- बाउंड है, तो एसिंक्रोन I / O के साथ सहकारी मल्टीटास्किंग संभवतः तुल्यकालिक थ्रेड-आधारित I / O की तुलना में अधिक कुशल (अर्थात अधिक थ्रूपुट) होगा; यदि आपका प्रोग्राम सीपीयू-बाउंड (उदाहरण के लिए लंबी गणना) है, तो सहकारी मल्टीटास्किंग बहुत कम उपयोगी होगी।
व्लादिमीर मतावेव

8

सहकारी निर्धारण अपराधी है। पैदावार के बिना, अन्य ("दुनिया" कहते हैं) गोरोइन को कानूनी तौर पर / जब मुख्य टर्मिनेशन से पहले निष्पादित करने के लिए शून्य संभावनाएं मिल सकती हैं, जो कि प्रति चश्मा सभी गोरटाइन को समाप्त करता है - यानी। संपूर्ण प्रक्रिया।


1
ठीक है, तो runtime.Gosched()पैदावार। इसका क्या मतलब है? यह मुख्य फ़ंक्शन पर नियंत्रण वापस लाता है?
जेसन यियो

5
इस विशिष्ट मामले में हाँ। आम तौर पर यह अनुसूचक को जानबूझकर अनिर्दिष्ट चयन क्रम में "तैयार" गोरआउट में से किसी एक को किक करने और चलाने के लिए कहता है।
zzzz
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.