গোরুটিন ব্যবস্থাপনা

গোরুটিন হল হালকা, তবে সেগুলি বিনামূল্যে নয়: কমপক্ষে মেমোরি এবং সিপিয়ু শিডিউলিং জন্য ব্যবহৃত হয়। গোরুটিন ব্যবহারে এই খরচগুলি ছোট, তবে ভারী সংখ্যক গোরুটিনের তৈরি যথাযথ জীবনচক্র না থাকলে গোরুটিন জনিত গতিতে গভীর ক্ষতির কারণ হতে পারে। অব্যবস্থিত জীবনচক্র সম্পন্ন গোরুটিন অসংগতি থেকে অন্যান্য সমস্যাও সৃষ্টি করতে পারে, যেমন: অব্যবহৃত অবজেক্টগুলির গার্বেজ কালেকশন থেকে বিরতি এবং ব্যবহৃত সম্পদ রাখা।

তাই, তোমার কোডে গোরুটিন বিচ্ছদ করবে না। গোরুটিনের জন্য গভীর বিশ্রাম সময় সাবধান করা দরকার। গোরুটিনের জন্য এইচএসটিয়াইলের go.uber.org/goleak ব্যবহার করে প্যাকেজে গোরুটিন লিক টেস্ট করুন।

সাধারণত, প্রতিটি গোরুটিপ্রয়োজন হবে:

  • একটি পূর্বাভাস সময়; বা
  • গোরুটিনের জন্য বার্তা পাঠানোর একটি উপায়।

উভয় মামলায়, কোডের জন্য গোরুটিন সম্পূর্ণ হওয়ার জন্য কোডের জন্য ব্লক এবং অপেক্ষা করার একটি উপায় থাকা দরকার।

উদাহরণ:

প্রশাস্তিত না:

go func() {
  for {
    flush()
    time.Sleep(delay)
  }
}()
// এই গোরুটিপ্রয়োজন. এটি অনিচ্ছাকৃনভাবে চলবে। এটি অসীমকাল চলবে যততো অ্যাপ্লিকেশনে।

প্রস্তাবিত:

var (
  stop = make(chan struct{}) // গোরুটিনের জন্য সংকেত দেওয়া
  done = make(chan struct{}) // ধরে রাখা যে গোরুটি শেষ হয়েছে
)
go func() {
  defer close(done)
  ticker := time.NewTicker(delay)
  defer ticker.Stop()
  for {
    select {
    case <-ticker.C:
      flush()
    case <-stop:
      return
    }
  }
}()

// ... অন্যান্য কোড
close(stop)  // ঘোষণা করে যে গোরুটিপ্রয়োজন বন্ধ করা হবে
<-done       // এবং এর জন্য অপেক্ষা করা

// এই গোরুটিপ্রয়োজনের বন্ধ করা close(stop) এবং এর জন্য অপেক্ষা করতে পারে আমরা.

গোরুটিন শেষ হওয়ার জন্য অপেক্ষা করা

যখন সিস্টেম দ্বারা তৈরি একটি গোরুটিন দেওয়া হয়, তখন এর জন্য শেষ হওয়ার জন্য অপেক্ষা করার একটি উপায় থাকা দরকার। এর জন্য দুটি সাধারণ পদ্ধতি আছে:

  • sync.WaitGroup ব্যবহার করা: এই মেথডটি ব্যবহার করুন যখন একাধিক গোরুটিনের জন্য অপেক্ষা করা হবে।
var wg sync.WaitGroup
for i := 0; i < num; i++ {
    wg.Add(1)
    go func() {
        defer wg.Done()
        // ...
    }()
}
wg.Wait()
  • অন্য একটি chan struct{} যোগ করা, এবং তার পরে সেটি বন্ধ করা যখন গোরুটিন সম্পূর্ণ হবে। যদি অন্যান্য কোন গোরুটিন না থাকে তাহলে এই উপায়টি ব্যবহার করুন।
done := make(chan struct{})
go func() {
    defer close(done)
    // ...
}()
// গোরুটিন সম্পূর্ণ হওয়ার জন্য অপেক্ষা করার জন্য:
<-done

init() ফাংশন গোরুটিন তৈরি করা উচিৎ নয়। এছাড়াও, init() এর ব্যবহার এড়িয়ে চলুন

যদি একটি প্যাকেজে ব্যাকগ্রাউন্ড গোরুটিন প্রয়োজন হয়, তবে সেই প্যাকেজ গোরুটিনের জীবনচক্র পরিচালনার জন্য দায়িত্বশীল একটি অবজেক্ট অবলম্বন করা উচিৎ। এই অবজেক্টটি প্রদান করা উচিৎ একটি মেথড (বন্ধ, পরিস্থিতি, শাটডাউন, ইত্যাদি) যাতে ব্যাকগ্রাউন্ড গোরুটিনের সমাপ্তি নির্দেশ করা এবং এর প্রস্থান অপেক্ষা করা।

প্রস্তাবিত পদ্ধতি:

func init() {
    go doWork()
}
func doWork() {
    for {
        // ...
    }
}
// যখন ব্যবহারকারী প্যাকেজটি নির্যাতনে তোমার সেই প্যাকেজে নৃতনগত গোরুটিন অগ্রগ঩্যগণ্য। ব্যবহারকারীরা গোরুটিনটি নিয়ন্ত্রণ করতে পারে না বা তা বন্ধ করতে পারে না।

প্রস্তাবিত পদ্ধতি:

type Worker struct{ /* ... */ }
func NewWorker(...) *Worker {
    w := &Worker{
        stop: make(chan struct{}),
        done: make(chan struct{}),
        // ...
    }
    go w.doWork()
}
func (w *Worker) doWork() {
    defer close(w.done)
    for {
        // ...
        select {
        case <-w.stop:
            return
        }
    }
}
// শাটডাউন শ্রমিক ধরার জন্য বলে
// এবং এর জন্য অপেক্ষা করে।
func (w *Worker) Shutdown() {
    close(w.stop)
    <-w.done
}

প্রয়োগকারীর অনুরোধে শ্রমিককে শুধুমাত্র তার দ্বারা অনুরোধ করা হলে উইকার তৈরি করুন, এবং ব্যবহারকারীকে শ্রমিকের ব্যবহৃত সম্পদগুলি মুক্তি দিতে শ্রমিকের বন্ধ করার একটি উপায় প্রদান করুন।

মনে রাখবেন, যদি শ্রমিক একাধিক গোরুটিন ব্যবস্থাপনা করে, তাহলে WaitGroup ব্যবহার করা উচিত।