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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ