Go Academy · درس

اتجاه القنوات وأنماط خطوط الأنابيب

القنوات للقراءة فقط والكتابة فقط وخطوط الأنابيب

الدرس 4 من 412 خطوة

اتجاه القنوات وأنماط خطوط الأنابيب درس مجاني في Go Academy على CoddyKit. هذا هو الدرس 4 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Go Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Go Academy 4 دروس في المجموع.

أنواع القنوات أحادية الاتجاه

تتيح Go تقييد القنوات لتكون للإرسال فقط أو للاستقبال فقط في تواقيع الأنواع. وهذا يوثّق الغرض ويمنع إساءة الاستخدام:

package main

// send-only: can only send, not receive or close (close is allowed by sender)
func sender(out chan<- int) {
    out <- 42
}

// receive-only: can only receive, not send or close
func receiver(in <-chan int) int {
    return <-in
}

// bidirectional: can do both
func relay(in <-chan int, out chan<- int) {
    out <- <-in
}

تحويل اتجاهات القنوات

يمكن تحويل قناة ثنائية الاتجاه ضمنيًا إلى أي من النوعين أحاديي الاتجاه، ولكن لا يمكن إجراء التحويل العكسي:

package main
import "fmt"

func produce(out chan<- int) { out <- 1; close(out) }
func consume(in <-chan int)  { fmt.Println(<-in) }

func main() {
    ch := make(chan int)   // bidirectional
    go produce(ch)         // auto-converts to chan<- int
    consume(ch)            // auto-converts to <-chan int
    // chan<- int cannot be converted back to <-chan int
}

المسار: المرحلة 1 — المُولِّد

يربط المسار الغوروتينات، بحيث تقرأ كل مرحلة من قناة خرج المرحلة السابقة. والمُولِّد هو المرحلة الأولى:

package main
import "fmt"

func generate(nums ...int) <-chan int {
    out := make(chan int)
    go func() {
        for _, n := range nums {
            out <- n
        }
        close(out)
    }()
    return out
}

func main() {
    ch := generate(2, 3, 4, 5)
    for v := range ch { fmt.Println(v) }
}

المسار: المرحلة 2 — التحويل

تستقبل المراحل الوسطى من قناة، وتحوّل البيانات، ثم ترسلها إلى قناة أخرى:

package main
import "fmt"

func generate(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 v := range in { out <- v * v }
        close(out)
    }()
    return out
}

func main() {
    for v := range square(generate(2, 3, 4, 5)) {
        fmt.Println(v)  // 4, 9, 16, 25
    }
}

المسار: مثال كامل من ثلاث مراحل

ربط ثلاث مراحل — التوليد والتحويل والتصفية:

package main
import "fmt"

func gen(nums ...int) <-chan int {
    c := make(chan int)
    go func() { for _, n := range nums { c <- n }; close(c) }()
    return c
}

func double(in <-chan int) <-chan int {
    c := make(chan int)
    go func() { for v := range in { c <- v * 2 }; close(c) }()
    return c
}

func evens(in <-chan int) <-chan int {
    c := make(chan int)
    go func() { for v := range in { if v%2 == 0 { c <- v } }; close(c) }()
    return c
}

func main() {
    for v := range evens(double(gen(1,2,3,4,5))) {
        fmt.Println(v)  // 2, 4, 6, 8, 10
    }
}

إلغاء المسار باستخدام قناة done

مرّروا قناة done للسماح لمراحل المسار بالخروج مبكرًا عند الإلغاء:

package main
import "fmt"

func gen(done <-chan struct{}, nums ...int) <-chan int {
    out := make(chan int)
    go func() {
        defer close(out)
        for _, n := range nums {
            select {
            case out <- n:
            case <-done:  // cancel signal
                return
            }
        }
    }()
    return out
}

func main() {
    done := make(chan struct{})
    ch := gen(done, 1, 2, 3, 4, 5)
    fmt.Println(<-ch)  // 1
    close(done)        // cancel remaining work
    fmt.Println("pipeline cancelled")
}

Fan-out: توزيع العمل

يوزّع Fan-out العمل من قناة واحدة إلى عدة غوروتينات لمعالجته بالتوازي:

package main
import ("fmt"; "sync")

func fanOut(in <-chan int, workers int) []<-chan int {
    outs := make([]<-chan int, workers)
    for i := 0; i < workers; i++ {
        out := make(chan int)
        outs[i] = out
        go func() {
            for v := range in { out <- v * v }  // each worker processes
            close(out)
        }()
    }
    return outs
}

func main() {
    fmt.Println("fan-out distributes work to multiple goroutines")
    _ = sync.WaitGroup{}
}

Fan-in: دمج القنوات

تدمج Fan-in قنوات متعددة في قناة واحدة:

package main
import ("fmt"; "sync")

func merge(cs ...<-chan int) <-chan int {
    out := make(chan int)
    var wg sync.WaitGroup
    for _, c := range cs {
        wg.Add(1)
        c := c
        go func() { defer wg.Done(); for v := range c { out <- v } }()
    }
    go func() { wg.Wait(); close(out) }()
    return out
}

func gen(nums ...int) <-chan int {
    c := make(chan int)
    go func() { for _, n := range nums { c <- n }; close(c) }()
    return c
}

func main() {
    for v := range merge(gen(1,2), gen(3,4), gen(5,6)) {
        fmt.Println(v)
    }
}

أفضل ممارسات خطوط الأنابيب

مبادئ تصميم خطوط الأنابيب:

  • كل مرحلة: يقرأ goroutine من <-chan، ويكتب إلى chan<-، ويغلق قناة الإخراج عند الانتهاء
  • المنتِج وحده يغلق القناة — وليس المستهلِك أبدًا
  • مرّر قناة done (أو سياقًا) للإلغاء
  • استخدم أنواع القنوات الاتجاهية في جميع تواقيع الدوال
  • فرّغ القنوات عند الإلغاء لمنع تسرّب goroutine

خط أنابيب عملي: معالجة CSV

تتألق خطوط الأنابيب في معالجة البيانات — قراءة الأسطر، وتحليلها، وتصفيتها، وتحويلها:

package main
import ("fmt"; "strings")

func splitLines(data string) <-chan string {
    out := make(chan string)
    go func() {
        for _, line := range strings.Split(data, "\n") {
            if line != "" { out <- line }
        }
        close(out)
    }()
    return out
}

func main() {
    csv := "alice,30\nbob,25\ncarol,35"
    for line := range splitLines(csv) {
        parts := strings.Split(line, ",")
        fmt.Printf("name=%s age=%s\n", parts[0], parts[1])
    }
}

تحقق سريع

ما الغرض من استخدام أنواع القنوات الاتجاهية في تواقيع الدوال؟

مراجعة: اتجاه القنوات وخطوط الأنابيب

الملخص:

  • chan<- T للإرسال فقط، و<-chan T للاستقبال فقط — لتوثيق القصد وتحقيق أمان وقت الترجمة
  • خطوط الأنابيب: ربط goroutine بحيث يقرأ كل منها من قناة ويكتب إلى قناة أخرى
  • Fan-out: قناة إدخال واحدة ← عدة goroutine
  • Fan-in: قنوات متعددة ← دمجها في قناة واحدة
  • أغلق القنوات دائمًا من جهة المُرسِل؛ واستخدم قناة done للإلغاء
البدء مجانًا

تعلم Go مع معلم ذكاء اصطناعي — مجانًا

اكتب وقم بتشغيل أكوادك الفعلية في المتصفح، واحصل على مساعدة فورية من معلم ذكاء اصطناعي متاح 24/7، واستمر من حيث توقفت على الويب أو في التطبيق.

الدورات
51
الدروس
203

الأسئلة الشائعة

هل درس «اتجاه القنوات وأنماط خطوط الأنابيب» مجاني؟

نعم — نص درس «اتجاه القنوات وأنماط خطوط الأنابيب» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Go Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Go Academy 4 دروس في المجموع.

ماذا ستتعلم في «اتجاه القنوات وأنماط خطوط الأنابيب»؟

القنوات للقراءة فقط والكتابة فقط وخطوط الأنابيب تتمرن على Go Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ Go Academy؟

لا تُشترط خبرة سابقة. Go Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 4 من أصل 4.

كم من الوقت يستغرق درس «اتجاه القنوات وأنماط خطوط الأنابيب»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس Go Academy هذا؟

نعم. كل درس في Go Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. تشغيل Goroutines
  2. القنوات غير المخزَّنة
  3. القنوات المخزَّنة
  4. اتجاه القنوات وأنماط خطوط الأنابيب
← العودة إلى Go Academy