0Pricing
Go Academy · บทเรียน

Fan-Out Fan-In

กระจายและรวบรวมงาน

Fan-Out Fan-In เป็นบทเรียน Go Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Go Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Go Academy มีบทเรียนทั้งหมด 4 บทเรียน

การกระจายงานและการรวมงาน

การกระจายงาน หมายถึงการเริ่มกอรูทีนหลายตัวเพื่ออ่านจากแชนเนลเดียวและแบ่งงานกันทำ ส่วน การรวมงาน หมายถึงการรวมผลลัพธ์จากกอรูทีนหลายตัวกลับเข้าเป็นแชนเนลเดียว

  • การกระจายงานช่วยแบ่งภาระให้เวิร์กเกอร์
  • การรวมงานช่วยรวบรวมผลลัพธ์ให้ผู้ใช้ผลลัพธ์

stage ตัวสร้าง

ไปป์ไลน์เริ่มต้นด้วยตัวสร้าง ซึ่งเป็นฟังก์ชันที่ส่งคืนแชนเนลและป้อนค่าลงในแชนเนลจากกอรูทีนของตัวเอง จากนั้นจึงปิดแชนเนล

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

การกระจายงาน

หากต้องการกระจายงาน ให้เริ่มกอรูทีนหลายตัวที่อ่านจากแชนเนลข้อมูลเข้าเดียวกัน ทุกตัวจะใช้ฟังก์ชันประมวลผลเดียวกันและสร้างแชนเนลผลลัพธ์ของตัวเอง

in := gen(1, 2, 3, 4, 5)
c1 := square(in)
c2 := square(in)

stage ประมวลผล

stage square อ่านค่าจาก in ยกกำลังสองให้แต่ละค่า แล้วส่งค่าไปยังแชนเนลผลลัพธ์ใหม่ อินสแตนซ์หลายตัวของ stage นี้ใช้ข้อมูลเข้าร่วมกัน

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 ใช้ติดตามกอรูทีนของแต่ละแชนเนล และกอรูทีนสำหรับปิดแชนเนลจะรอให้กอรูทีนทั้งหมดเสร็จสิ้นก่อนปิดผลลัพธ์ที่รวมแล้ว

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

กอรูทีนสำหรับรวมแต่ละตัวจะคัดลอกข้อมูลจากแชนเนลข้อมูลเข้าหนึ่งแชนเนลไปยัง out เราต้องไม่ปิด out จนกว่าจะอ่านข้อมูลเข้าทุกแชนเนลจนหมด WaitGroup จะนับจำนวนตัวคัดลอกที่กำลังทำงานอยู่ ส่วนกอรูทีนสำหรับปิดแชนเนลจะหยุดรอที่ wg.Wait() จนกว่าทั้งหมดจะเสร็จสิ้น

การเก็บค่าตัวแปรในวงรอบ

ในภาษา Go รุ่นเก่า ฟังก์ชันปิดล้อมต้องรับ c เป็นพารามิเตอร์ เพื่อให้กอรูทีนแต่ละตัวผูกกับแชนเนลของตัวเองแทนที่จะใช้ตัวแปรในวงรอบร่วมกัน การส่ง c อย่างชัดเจนช่วยหลีกเลี่ยงข้อผิดพลาดคลาสสิกของตัวแปรในวงรอบ

การกระจายและรวมงานอย่างสมบูรณ์

โปรแกรมนี้สร้างตัวเลข กระจายงานไปยัง stage square สองตัว จากนั้นรวมงานกลับเข้าด้วยกันและหาผลรวมของผลลัพธ์ที่รวมแล้ว

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)
}

ไม่รับประกันลำดับ

เนื่องจาก stage square สองตัวแข่งขันกันอ่านข้อมูลเข้าเดียวกัน ลำดับของผลลัพธ์ที่รวมแล้วจึงไม่แน่นอน หากต้องการรักษาลำดับ ให้แนบดัชนีไปกับแต่ละรายการหรือใช้ stage เดียว

เมื่อใดควรกระจายงาน

ให้กระจายงานเมื่อ stage เป็นคอขวดและงานสามารถทำแบบขนานได้ หากตัวสร้างต้นทางทำงานช้า การเพิ่มเวิร์กเกอร์ปลายทางจะไม่ช่วย เพราะเวิร์กเกอร์เหล่านั้นจะไม่มีงานทำ

แรงดันย้อนกลับ

แชนเนลที่ไม่มีบัฟเฟอร์สร้างแรงดันย้อนกลับตามธรรมชาติ: stage ที่ทำงานเร็วจะหยุดรอเมื่อผู้ใช้ผลลัพธ์ที่ช้าไม่สามารถประมวลผลตามได้ทัน วิธีนี้ป้องกันไม่ให้การใช้หน่วยความจำทั่วทั้งไปป์ไลน์เพิ่มขึ้นอย่างไม่จำกัด

ตรวจสอบความเข้าใจอย่างรวดเร็ว

ทดสอบความเข้าใจของคุณเกี่ยวกับการรวมงาน

สรุปทบทวน

คุณได้เรียนรู้การกระจายงานและการรวมงานดังนี้:

  • การกระจายงาน: กอรูทีนหลายตัวอ่านจากแชนเนลเดียว
  • การรวมงาน: รวมแชนเนลหลายแชนเนลให้เป็นหนึ่งเดียวผ่าน WaitGroup
  • ลำดับจะไม่คงเดิมเมื่อผ่าน stage แบบขนาน
  • แชนเนลที่ไม่มีบัฟเฟอร์ช่วยสร้างแรงดันย้อนกลับ

คำถามที่พบบ่อย

บทเรียน “Fan-Out Fan-In” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “Fan-Out Fan-In” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Go Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Go Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “Fan-Out Fan-In”

กระจายและรวบรวมงาน คุณปฏิบัติ Go Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Go Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Go Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน

บทเรียน “Fan-Out Fan-In” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Go Academy นี้ได้ไหม

ได้ บทเรียน Go Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. รูปแบบกลุ่มผู้ปฏิบัติงาน
  2. Fan-Out Fan-In
  3. ขั้นตอนของกระบวนการประมวลผล
  4. การปิดระบบอย่างราบรื่น
← กลับไปที่ Go Academy