मुख्य सामग्री पर जाएं
मॉड्यूल 7 · पाठ 3 का 5पाठ्यक्रम में 33/50~12 min
मॉड्यूल पाठ (3/5)

`चयन करें`: मल्टीप्लेक्सिंग चैनल

select एक ही समय में एकाधिक चैनल संचालन पर प्रतीक्षा करता है। यह गो संगामिति का switch है: यह आपको पहले पर प्रतिक्रिया करने देता है कई लोगों के बीच चैनल तैयार।

सिंटेक्स

Go
select {
case v := <-ch1:
    fmt.Println("ch1:", v)
case v := <-ch2:
    fmt.Println("ch2:", v)
case ch3 <- 99:
    fmt.Println("inviato su ch3")
case <-time.After(time.Second):
    fmt.Println("timeout")
default:
    fmt.Println("nessuno è pronto")
}

शब्दार्थ:

  • सभी मामलों का मूल्यांकन किया जाता है; तैयार मामलों में से केवल एक को चुना जाता है।
  • यदि एकाधिक मामले तैयार हैं, तो विकल्प छद्म-यादृच्छिक (कोई ऑर्डर नहीं) है।
  • यदि कोई मामला तैयार नहीं है: select तब तक ब्लॉक रहता है जब तक कोई मामला तैयार नहीं हो जाता।
  • यदि कोई default है: कोई केस तैयार नहीं होने पर यह तुरंत चलता है (नॉन-ब्लॉकिंग चयन करें)।

टाइमआउट पैटर्न

Go
select {
case res := <-fetch(url):
    use(res)
case <-time.After(2 * time.Second):
    log.Println("timeout: fetch troppo lento")
}

time.After(d) एक <-chan Time लौटाता है जो d के बाद एक मान उत्पन्न करता है। यह प्रतीक्षा को बांधने का उत्कृष्ट तरीका है।

डिफ़ॉल्ट के साथ गैर-अवरुद्ध चयन करें

Go
select {
case msg := <-ch:
    process(msg)
default:
    // niente da fare, prosegui
}

यह चैनल को बिना ब्लॉक किए "पोल" करता है। कोड पथों में उपयोगी अनिवार्य रूप से प्रतीक्षा किए बिना उत्तरदायी रहना चाहिए।

"संपन्न चैनल" पैटर्न

select को रद्दीकरण चैनल के साथ संयोजित करें:

Go
func worker(in <-chan Job, done <-chan struct{}) {
    for {
        select {
        case j := <-in:
            process(j)
        case <-done:
            return       // chi gestisce done segnala lo shutdown
        }
    }
}

समन्वयक की ओर से close(done) प्रत्येक में case <-done को ट्रिगर करता है वेटिंग गोरोइन: समन्वित शटडाउन।

चयन के साथ लूप करें

Go
for {
    select {
    case v := <-input:
        if v == nil {
            return
        }
        handle(v)
    case <-time.After(5 * time.Second):
        keepAlive()
    case <-ctx.Done():
        return
    }
}

सर्वर और कर्मचारियों के लिए विशिष्ट "इवेंट लूप" पैटर्न।

"अक्षम" मामले के रूप में एक शून्य चैनल

एक उन्नत युक्ति: ch == nil के साथ case <-ch कभी नहीं होता है चयनित. यह आपको किसी मामले को गतिशील रूप से "अक्षम" करने देता है:

Go
var in chan int = source()
for {
    select {
    case v, ok := <-in:
        if !ok {
            in = nil    // disabilita questo case
            continue
        }
        handle(v)
    case <-ctx.Done():
        return
    }
}

जब in बंद हो जाता है, तो मैं इसे रद्द कर देता हूं: select केवल संभालता रहता है अन्य मामले.

इसे अजमाएं

व्यायाम#go.m7.l3.e1
प्रयास: 0लोड हो रहा है...

ch1 और ch2 से प्राप्त होने वाले दो मामलों के साथ चयन लागू करें; प्रिंट करें कि कौन पहले आया।

संपादक लोड हो रहा है...
संकेत दिखाएँ

प्रति चैनल एक केस के साथ सिंटैक्स `सेलेक्ट {केस ...: ... }`।

3 प्रयासों के बाद समाधान उपलब्ध है

व्यायाम#go.m7.l3.e2
प्रयास: 0लोड हो रहा है...

time.After(time.Second) का उपयोग करके चयन में एक टाइमआउट केस जोड़ें।

संपादक लोड हो रहा है...
संकेत दिखाएँ

`time.After(d)` एक चैनल है जो d के बाद प्राप्त होता है।

3 प्रयासों के बाद समाधान उपलब्ध है

Quiz#go.m7.l3.e3
तैयार

क्या चीज़ किसी चयन को गैर-अवरुद्ध बनाती है?

Go
select { case v := <-ch: ... ??? }
उत्तर विकल्प

संक्षिप्त

  • select कई चैनल परिचालनों के बीच पहले तैयार मामले की प्रतीक्षा कर रहा है।
  • कई तैयार मामलों के बीच छद्म यादृच्छिक विकल्प।
  • default → गैर-अवरुद्ध चयन (मतदान)।
  • टाइमआउट के लिए time.After(d) (लूप में लीक को ध्यान में रखें: context का उपयोग करें)।
  • पैटर्न: किसी मामले को अक्षम करने के लिए पूर्ण चैनल, ईवेंट लूप, शून्य चैनल।
  • खाली select{} = शाश्वत ब्लॉक: लगभग हमेशा एक बग।