sync.WaitGroup
انتظار مجموعة من Goroutines
sync.WaitGroup درس مجاني في Go Academy على CoddyKit. هذا هو الدرس 2 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Go Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Go Academy 4 دروس في المجموع.
الغرض
sync.WaitGroup ينتظر اكتمال مجموعة من goroutines. تستدعي goroutine الرئيسية Add لتعيين العدد، وتستدعي كل goroutine Done عند اكتمالها، بينما تحجب Wait التنفيذ حتى يصل العدد إلى الصفر.
الاستخدام الأساسي
استدعِ Add قبل تشغيل كل goroutine؛ واستدعِ Done في نهاية كل goroutine (باستخدام defer)؛ واستدعِ Wait بعد تشغيل جميع goroutines.
var wg sync.WaitGroup
for _, item := range items {
wg.Add(1)
go func(v Item) {
defer wg.Done()
process(v)
}(item)
}
wg.Wait()يجب استدعاء Add قبل بدء goroutine
استدعِ wg.Add(1) قبل go func()، وليس داخل goroutine مطلقًا. وإلا فقد تعود Wait قبل أن تسجّل goroutine نفسها.
خطأ شائع: التقاط متغير الحلقة
مرّر متغير الحلقة وسيطًا إلى دالة goroutine، وليس عبر closure، لتجنب مشاركة جميع goroutines للمتغير نفسه.
for _, v := range items {
wg.Add(1)
go func(item Item) { // correct: copy
defer wg.Done()
process(item)
}(v)
}إعادة استخدام WaitGroup
يمكن إعادة استخدام WaitGroup بعد عودة Wait، ولكن فقط بعد اكتمال جميع استدعاءات Done السابقة. لا تعِد استخدامه بالتزامن مع وجود استدعاءات Done لم تكتمل بعد.
WaitGroup مع النتائج
لا يجمع WaitGroup النتائج — ادمجه مع channel أو slice (باستخدام Mutex) لجمع المخرجات من goroutines.
results := make([]Result, len(items))
for i, item := range items {
wg.Add(1)
go func(idx int, v Item) {
defer wg.Done()
results[idx] = process(v)
}(i, item)
}
wg.Wait()Add باستخدام العدد الإجمالي
يمكنك تمرير العدد الإجمالي إلى استدعاء Add واحد قبل الحلقة، وهذا أكثر كفاءة قليلًا من استدعاء Add مرة لكل goroutine.
wg.Add(len(items))
for _, item := range items {
go func(v Item) { defer wg.Done(); process(v) }(item)
}لا تنسخ WaitGroup
مثل Mutex، يجب عدم نسخ WaitGroup بعد أول استخدام. مرّره بواسطة مؤشر أو ضمّنه في بنية تُمرَّر بواسطة مؤشر.
WaitGroup مقابل errgroup
golang.org/x/sync/errgroup يغلّف WaitGroup ويضيف تمرير الأخطاء. فضّل errgroup عندما ينبغي أن يؤدي فشل أي goroutine إلى إيقاف البقية.
الدمج مع context
استخدم errgroup.WithContext للحصول على دلالات WaitGroup وسياق يُلغى عند أول خطأ، ما يوقف جميع goroutines بطريقة نظيفة.
g, ctx := errgroup.WithContext(context.Background())
g.Go(func() error { return doWork(ctx) })
if err := g.Wait(); err != nil { log.Fatal(err) }القيمة الصفرية قابلة للاستخدام
القيمة الصفرية لـ sync.WaitGroup جاهزة للاستخدام — ولا تحتاج إلى مُنشئ. صرّح به واستدعِ Add فحسب.
اختبار سريع
ماذا يحدث إذا استدعيت wg.Add(1) داخل goroutine بدلًا من استدعائها قبل تشغيلها؟
مراجعة: sync.WaitGroup
النقاط الأساسية:
- استدعِ Add قبل تشغيل goroutine؛ واستدعِ Done باستخدام defer داخل goroutine
- تحجب Wait التنفيذ حتى يصل العدد إلى الصفر
- لا تنسخه مطلقًا؛ ولا تستدعِ Add داخل goroutine
- استخدم errgroup لتمرير الأخطاء
الأسئلة الشائعة
هل درس «sync.WaitGroup» مجاني؟
نعم — نص درس «sync.WaitGroup» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Go Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Go Academy 4 دروس في المجموع.
ماذا ستتعلم في «sync.WaitGroup»؟
انتظار مجموعة من Goroutines تتمرن على Go Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ Go Academy؟
لا تُشترط خبرة سابقة. Go Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 2 من أصل 4.
كم من الوقت يستغرق درس «sync.WaitGroup»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس Go Academy هذا؟
نعم. كل درس في Go Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.