سؤال

البيئة: OS X 10.8 ، اذهب 1.0.2

أقوم بعمل قناة ذات حجم مخزن مؤقت 2 ، ثم إذا كتبت قناة ثلاث مرات ، فسترمي خطأ:

رمي: جميع goroutines نائمة - deadlock!

بالطبع ، هذا صحيح.

لكن إذا كتبت القناة أربع مرات أو أكثر في goroutines ، فهذا يعمل بشكل جيد ، لماذا؟ قدرة القناة 2 ، لماذا تتجاهل goroutines ذلك أو تنسى إعداد السعة؟ أعلق رموز القناة القراءة ، لذلك لن يقرأ أحد القناة ويحفظ السعة. أنا أيضًا أستخدم الوقت. seleep لانتظار جميع goroutines إنهاء عملهم.

يرجى مراجعة الرموز التالية: الحزمة الرئيسية

//import "fmt"

func main() {
    c := make(chan int, 2)
    /*c <- 1
    c <- 2
    c <- 3*/
    for i:=0; i<4; i++ {
        go func(i int) {
            c <- i
            c <- 9
            c <- 9
            c <- 9
        }(i)
    }
    time.Sleep(2000 * time.Millisecond)

    /*for i:=0; i<4*2; i++ {
        fmt.Println(<-c)
    }*/
}

هل من فضلك من فضلك أعطي بعض الزيارات؟ شكرا يا رفاق.

هل كانت مفيدة؟

المحلول

عندما يتم تخزين القناة ، فإن هذا يعني أنه لن يتم حظره حتى يتم امتلاء المخزن المؤقت. بمجرد امتلاء المخزن المؤقت ، سيتم حظر Goroutine المرسل لأنه يحاول إضافة أشياء إلى القناة.

هذا يعني أن هذا سيحظر:

c := make(chan int)
c <- 1          // Block here, this is unbuffered !
println(<-c)

وهذه الإرادة ايضا الكتلة:

c := make(chan int, 2)
c <- 1
c <- 2
c <- 3           // Block here, buffer is full !
println(<-c)

لكن ال نقطة من goroutines والقناة هو على وجه التحديد تشغيل الأشياء في وقت واحد ، لذلك سوف ينجح هذا:

c := make(chan int)
go func() { c <- 1; }() // This will block in the spawned goroutine until...
println(<-c)            // ... this line is reached in the main goroutine

وبالمثل:

c := make(chan int, 2)
go func() {  // `go ...` spawns a goroutine
    c <- 1   // Buffer is not full, no block
    c <- 2   // Buffer is not full, no block
    c <- 3   // Buffer is full, spawned goroutine is blocking until...
}()
println(<-c) // ... this line is reached in the main goroutine

في مثالك ، تفرخ أربعة goroutines المختلفة ، والتي تكتب جميعها أربعة أرقام إلى نفس القناة المخزنة. نظرًا لأن المخزن المؤقت هو 2 <16 ، فسوف ينتهي بهم المطاف إلى الحجب

لكن جوهر الأمر هو أن سياسة GO هي انتظر فقط من أجل goroutine الرئيسي:

يبدأ تنفيذ البرنامج عن طريق تهيئة الحزمة الرئيسية ثم استدعاء الوظيفة الرئيسية. عندما تعود الوظيفة الرئيسية ، يخرج البرنامج. لا ينتظر إكمال goroutines (غير مين).

هذا يعني أنه في المثال الأول ، رئيسي كان جوروتين يحظر عندما وصل إلى الخط c <- 3. نظرًا لعدم تمكن Goroutine من فعل أي شيء يمكن أن يفصله ، اكتشف وقت التشغيل أن البرنامج قد تم مسدود وأبلغ عن خطأ.

في مثالك الثاني ، ومع ذلك ، ولدت كتلة goroutines ، بينما يستمر الرئيسي بهدوء حتى يصل إلى نهاية تنفيذها ، وعند هذه النقطة يتم قتل جميع goroutines (المحظورة) بصمت ، ولم يتم الإبلاغ عن أي خطأ.

نصائح أخرى

فال أعطى إجابة جيدة. أرغب في إضافة نصيحة إضافية وجدت أنها مفيدة.

عند تعلم استخدام goroutines ، استخدم قنوات ذات صفر لتبدأ. وبهذه الطريقة ، عندما ترتكب خطأ ، ستحصل على الفور على طريق مسدود ، يمكنك التعلم منه. تحتاج إلى معرفة كيفية كتابة التعليمات البرمجية التي لا تطفو ، مما يعني تعلم الحيل مثل عدم وجود تبعيات دورية في علاقات خادم العميل (على افتراض أن goroutines مكتوبة كعملاء أو خوادم).

التفكير في الشبكة دون التخزين المؤقت أكثر بساطة ، على الرغم من أن هذا قد لا يكون واضحًا في البداية.

التخزين المؤقت مفيدًا حقًا ، ولكن ينبغي اعتباره وسيلة لتعزيز الأداء.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top