সিঙ্কের উদাহরণ? ওয়েটগ্রুপ সঠিক?


108

এই উদাহরণ sync.WaitGroupসঠিক ব্যবহার ? এটি প্রত্যাশিত ফলাফল দেয় তবে আমি wg.Add(4)এবং এর অবস্থান সম্পর্কে নিশ্চিত নই wg.Done()। একসাথে চারটি গোরোটিন যুক্ত করার অর্থ wg.Add()কী?

http://play.golang.org/p/ecvYHiie0P

package main

import (
    "fmt"
    "sync"
    "time"
)

func dosomething(millisecs time.Duration, wg *sync.WaitGroup) {
    duration := millisecs * time.Millisecond
    time.Sleep(duration)
    fmt.Println("Function in background, duration:", duration)
    wg.Done()
}

func main() {
    var wg sync.WaitGroup
    wg.Add(4)
    go dosomething(200, &wg)
    go dosomething(400, &wg)
    go dosomething(150, &wg)
    go dosomething(600, &wg)

    wg.Wait()
    fmt.Println("Done")
}

ফলাফল (প্রত্যাশারূপে):

Function in background, duration: 150ms
Function in background, duration: 200ms
Function in background, duration: 400ms
Function in background, duration: 600ms
Done

1
ডোজোমিং () ডাব্লু.জি। ডোন () করার আগে ক্রাশ হয়ে গেলে কী হবে?
মোস্তোস্কি

19
আমি বুঝতে পারি যে এটি পুরানো, তবে ভবিষ্যতের লোকদের জন্য, আমি defer wg.Done()ফাংশনটি শুরু করার সময় একটি প্রাথমিক কলটি সুপারিশ করব ।
ব্রায়ান

উত্তর:


154

হ্যাঁ, এই উদাহরণটি সঠিক। জাতিদের শর্ত রোধ wg.Add()করতে goবিবৃতি দেওয়ার আগে এটি হওয়া জরুরি important নিম্নলিখিতগুলিও সঠিক হবে:

func main() {
    var wg sync.WaitGroup
    wg.Add(1)
    go dosomething(200, &wg)
    wg.Add(1)
    go dosomething(400, &wg)
    wg.Add(1)
    go dosomething(150, &wg)
    wg.Add(1)
    go dosomething(600, &wg)

    wg.Wait()
    fmt.Println("Done")
}

তবে, wg.Addআপনি ইতিমধ্যে জানেন যে এটি কতবার কল করা হবে তা বার বার কল করা অর্থহীন ।


Waitgroupsকাউন্টার শূন্যের নিচে পড়লে আতঙ্কিত। কাউন্টার শূন্য থেকে শুরু হয়, প্রতিটি Done()এক -1এবং প্রতিটি Add()প্যারামিটারের উপর নির্ভর করে। সুতরাং, কাউন্টারটি কখনই নীচে নেমে না যায় এবং আতঙ্কগুলি এড়াতে Add()তা নিশ্চিত করতে আপনার আগে অবশ্যই গ্যারান্টি থাকা দরকার Done()

গো-তে, এই ধরনের গ্যারান্টি মেমরি মডেল দ্বারা দেওয়া হয় ।

মেমরি মডেলটিতে বলা হয়েছে যে একক গোরোটিনের সমস্ত বিবৃতি লিখিতভাবে একই ক্রমে কার্যকর হয় বলে মনে হয়। এটি সম্ভবত তারা সেই ক্রমে থাকবে না, তবে ফলাফলটি যেমন হবে তেমনই হবে। এটিও গ্যারান্টিযুক্ত যে কোনও গোরোটিন goযে বিবৃতি দেয় তার পরে যতক্ষণ না এটি চলবে । যেহেতু Add()আগে ঘটে goবিবৃতি এবং goবিবৃতি সামনে ঘটে Done(), আমরা জানি Add()সামনে ঘটে Done()

আপনার যদি goবিবৃতিটি আগে আসতে হয় Add()তবে প্রোগ্রামটি সঠিকভাবে পরিচালনা করতে পারে। তবে এটি কোনও রেসের শর্ত হবে কারণ এটির গ্যারান্টি নেই।


9
এই সম্পর্কে আমার একটি প্রশ্ন রয়েছে: এটি কী আরও ভাল হবে defer wg.Done()না যে আমরা নিশ্চিত যে গোরোটিন যে পথ নেয় তা নির্বিশেষে এটি বলা হয়? ধন্যবাদ।
আলেসান্দ্রো শান্তিনি

2
আপনি যদি বিশুদ্ধরূপে নিশ্চিত হয়ে যেতে চেয়েছিলেন যে সমস্ত গোটা রুটিন শেষ হওয়ার আগে ফাংশনটি ফিরে না আসে তবে হ্যাঁ ডিফেন্ডকেই অগ্রাধিকার দেওয়া হবে। কেবলমাত্র অপেক্ষার গোষ্ঠীর পুরো পয়েন্টটি সমস্ত কাজ সম্পন্ন হওয়া পর্যন্ত অপেক্ষা করা হয় তারপরে আপনি যে ফলাফলগুলির জন্য অপেক্ষা করছিলেন তা দিয়ে do
জানভেন

1
যদি আপনি ব্যবহার না করেন deferএবং আপনার গোরোটিনগুলির মধ্যে একটি কল করতে ব্যর্থ হয় wg.Done()... তবে কী আপনার Waitচিরকালের জন্য অবরুদ্ধ থাকবে না? এটির মতো মনে হচ্ছে এটি সহজেই আপনার কোডে একটি হার্ড-টু-বগ বাগটি প্রবর্তন করতে পারে ...
ড্যান এস্পারজা

29

আমি wg.Add()কলটি doSomething()নিজেই ফাংশনটিতে এম্বেড করার পরামর্শ দেব , যাতে আপনি যে বার বলা হয়েছে তার সংখ্যাটি সামঞ্জস্য করেন তবে আপনাকে পৃথকভাবে অ্যাড প্যারামিটারটি স্বয়ংক্রিয়ভাবে সামঞ্জস্য করতে হবে না যা যদি আপনি একটি আপডেট করেন তবে একটি ত্রুটি হতে পারে তবে আপডেটটি আপডেট করতে ভুলে যান অন্যান্য (এই তুচ্ছ উদাহরণে অসম্ভব, তবে এখনও, আমি ব্যক্তিগতভাবে এটি কোড পুনরায় ব্যবহারের জন্য আরও ভাল অনুশীলন বলে বিশ্বাস করি)।

স্টিফেন ওয়েইনবার্গ এই প্রশ্নের জবাবে যেভাবে উল্লেখ করেছেন, গোফঙ্কটি তৈরি করার আগে আপনাকে ওয়েটগ্রুপটি বাড়িয়ে তুলতে হবে, তবে আপনি doSomething()নিজেই ফাংশনটির ভিতরে গোফঙ্ক স্প্যানটি গুটিয়ে রেখে এটি সম্পাদন করতে পারবেন :

func dosomething(millisecs time.Duration, wg *sync.WaitGroup) {
    wg.Add(1)
    go func() {
        duration := millisecs * time.Millisecond
        time.Sleep(duration)
        fmt.Println("Function in background, duration:", duration)
        wg.Done()
    }()
}

তারপরে আপনি বিনা goআমন্ত্রণ ছাড়াই এটি কল করতে পারেন , যেমন:

func main() {
    var wg sync.WaitGroup
    dosomething(200, &wg)
    dosomething(400, &wg)
    dosomething(150, &wg)
    dosomething(600, &wg)
    wg.Wait()
    fmt.Println("Done")
}

খেলার মাঠ হিসাবে: http://play.golang.org/p/WZcprjpHa_


21
  • Mroth উত্তর উপর ভিত্তি করে ছোট উন্নতি
  • সম্পন্ন জন্য মুলতুবি ব্যবহার নিরাপদ
  func dosomething(millisecs time.Duration, wg *sync.WaitGroup) {
  wg.Add(1)
  go func() {
      defer wg.Done()
      duration := millisecs * time.Millisecond
      time.Sleep(duration)
      fmt.Println("Function in background, duration:", duration)
  }()
}

func main() {
  var wg sync.WaitGroup
  dosomething(200, &wg)
  dosomething(400, &wg)
  dosomething(150, &wg)
  dosomething(600, &wg)
  wg.Wait()
  fmt.Println("Done")
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.