التوزيع والتجميع
وزّع العمل واجمعه
التوزيع والتجميع درس مجاني في Go Academy على CoddyKit. هذا هو الدرس 2 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Go Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Go Academy 4 دروس في المجموع.
التوزيع والتجميع
يعني التوزيع (Fan-out) تشغيل عدة goroutines للقراءة من قناة واحدة وتوزيع العمل بينها. أما التجميع (Fan-in) فيعني دمج مخرجات عدة goroutines مرة أخرى في قناة واحدة.
- يوزّع التوزيع الحمل على العمال
- يجمع التجميع النتائج للمستهلك
مرحلة المولّد
يبدأ خط الأنابيب بمولّد: وهو دالة تُرجع قناة وتغذّيها بالقيم من goroutine الخاصة بها، ثم تغلقها.
func gen(nums ...int) <-chan int {
out := make(chan int)
go func() {
for _, n := range nums {
out <- n
}
close(out)
}()
return out
}التوزيع
لإجراء التوزيع، شغّل عدة goroutines تقرأ جميعها من قناة الإدخال نفسها. تنفّذ كل واحدة منها دالة المعالجة نفسها وتنتج قناة إخراج خاصة بها.
in := gen(1, 2, 3, 4, 5)
c1 := square(in)
c2 := square(in)مرحلة المعالجة
تقرأ مرحلة square من in، وتربّع كل قيمة، ثم ترسلها إلى قناة إخراج جديدة. تشترك عدة مثيلات من هذه المرحلة في إدخال واحد.
func square(in <-chan int) <-chan int {
out := make(chan int)
go func() {
for n := range in {
out <- n * n
}
close(out)
}()
return out
}التجميع باستخدام merge
يدمج التجميع عدة قنوات في قناة واحدة. يتتبّع sync.WaitGroup goroutines الخاصة بكل قناة، بينما تنتظر goroutine للإغلاق انتهاء جميعها قبل إغلاق مخرج الدمج.
func merge(cs ...<-chan int) <-chan int {
out := make(chan int)
var wg sync.WaitGroup
for _, c := range cs {
wg.Add(1)
go func(c <-chan int) {
for n := range c {
out <- n
}
wg.Done()
}(c)
}
go func() { wg.Wait(); close(out) }()
return out
}لماذا نستخدم WaitGroup
تنسخ كل goroutine مخصّصة للدمج قناة إدخال واحدة إلى out. يجب ألا نغلق out حتى يتم استنزاف كل قنوات الإدخال. يحصي WaitGroup عمليات النسخ النشطة، بينما تنتظر goroutine الإغلاق عند wg.Wait() حتى تنتهي جميعها.
التقاط متغير الحلقة
في إصدارات Go الأقدم، يجب أن تستقبل closure المتغير c كمعامل حتى تربط كل goroutine قناة خاصة بها، بدلًا من استخدام متغير الحلقة المشترك. يؤدي تمرير c صراحةً إلى تجنّب خطأ متغير الحلقة الشائع.
توزيع وتجميع متكاملان
ينشئ هذا البرنامج أرقامًا، ثم يوزّعها على مرحلتي تربيع، وبعد ذلك يجمّع النتائج المدمجة ويحسب مجموعها.
package main
import (
"fmt"
"sync"
)
func gen(nums ...int) <-chan int {
out := make(chan int)
go func() { for _, n := range nums { out <- n }; close(out) }()
return out
}
func square(in <-chan int) <-chan int {
out := make(chan int)
go func() { for n := range in { out <- n * n }; close(out) }()
return out
}
func merge(cs ...<-chan int) <-chan int {
out := make(chan int)
var wg sync.WaitGroup
for _, c := range cs {
wg.Add(1)
go func(c <-chan int) { for n := range c { out <- n }; wg.Done() }(c)
}
go func() { wg.Wait(); close(out) }()
return out
}
func main() {
in := gen(1, 2, 3, 4, 5)
c1 := square(in)
c2 := square(in)
total := 0
for n := range merge(c1, c2) {
total += n
}
fmt.Println("sum of squares:", total)
}الترتيب غير مضمون
بما أن مرحلتي التربيع تتنافسان على الإدخال نفسه، فإن ترتيب المخرجات المدمجة غير حتمي. إذا كنتم بحاجة إلى الحفاظ على الترتيب، فأضيفوا فهرسًا إلى كل عنصر أو استخدموا مرحلة واحدة.
متى نستخدم التوزيع
استخدموا التوزيع عندما تكون إحدى المراحل عنق الزجاجة ويكون العمل قابلًا للتنفيذ بالتوازي. وإذا كان المولّد في الجهة السابقة بطيئًا، فلن تساعد إضافة مزيد من العمال في الجهة اللاحقة، بل سيبقون من دون عمل.
الضغط العكسي
تنشئ القنوات غير المخزّنة ضغطًا عكسيًا طبيعيًا: إذ تتوقف المرحلة السريعة عندما يعجز المستهلك البطيء عن مواكبتها. ويمنع ذلك نمو الذاكرة بلا حدود عبر خط الأنابيب.
اختبار سريع
اختبروا معرفتكم بالتجميع.
مراجعة
تعلّمتم التوزيع والتجميع:
- التوزيع: عدة goroutines تقرأ من قناة واحدة
- التجميع: دمج عدة قنوات في قناة واحدة باستخدام WaitGroup
- لا يُحافَظ على الترتيب عبر المراحل المتوازية
- توفر القنوات غير المخزّنة ضغطًا عكسيًا
الأسئلة الشائعة
هل درس «التوزيع والتجميع» مجاني؟
نعم — نص درس «التوزيع والتجميع» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Go Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Go Academy 4 دروس في المجموع.
ماذا ستتعلم في «التوزيع والتجميع»؟
وزّع العمل واجمعه تتمرن على Go Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ Go Academy؟
لا تُشترط خبرة سابقة. Go Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 2 من أصل 4.
كم من الوقت يستغرق درس «التوزيع والتجميع»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس Go Academy هذا؟
نعم. كل درس في Go Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- نمط تجمع العاملين
- التوزيع والتجميع
- مراحل المسار
- إيقاف التشغيل بسلاسة