মূল কন্টেন্টে যান
মডিউল 7 · 3-এর পাঠ 5কোর্সে 33/50~12 min
মডিউল পাঠ (3/5)

`নির্বাচন`: মাল্টিপ্লেক্সিং চ্যানেল

select একই সময়ে একাধিক চ্যানেল অপারেশন এর জন্য অপেক্ষা করছে। এটি Go concurrency এর 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
    }
}

সার্ভার এবং কর্মীদের জন্য সাধারণ "ইভেন্ট লুপ" প্যাটার্ন।

একটি "অক্ষম" ক্ষেত্রে একটি শূন্য চ্যানেল

একটি উন্নত কৌশল: একটি case <-ch এর সাথে ch == nil কখনই নয় নির্বাচিত এটি আপনাকে গতিশীলভাবে একটি কেস "অক্ষম" করতে দেয়:

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{} = চিরন্তন ব্লক: প্রায় সবসময় একটি বাগ।