ทิศทางแชนเนลและรูปแบบไปป์ไลน์
แชนเนลสำหรับอ่านอย่างเดียว เขียนอย่างเดียว และไปป์ไลน์
ทิศทางแชนเนลและรูปแบบไปป์ไลน์ เป็นบทเรียน Go Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 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 — ตัวสร้าง
ไปป์ไลน์ เชื่อมต่อ goroutine หลายรายการ โดยแต่ละขั้นอ่านค่าจากช่องสัญญาณเอาต์พุตของขั้นก่อนหน้า ตัวสร้างคือลำดับขั้นแรก:
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
}
}ไปป์ไลน์: ตัวอย่างแบบสามขั้นตอนครบถ้วน
เชื่อมต่อสามขั้นตอน ได้แก่ generate, แปลง และกรอง:
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")
}การกระจายงาน: แบ่งงาน
การกระจายงานจะแจกจ่ายงานจากช่องสัญญาณหนึ่งไปยัง goroutine หลายรายการเพื่อประมวลผลพร้อมกัน:
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 รวมช่องสัญญาณหลายช่องให้เป็นหนึ่งช่อง:
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)
}
}แนวทางปฏิบัติที่ดีสำหรับไปป์ไลน์
หลักการออกแบบไปป์ไลน์:
- แต่ละขั้นตอน: โกโรทีนอ่านจาก
<-chanเขียนไปยังchan<-และปิดช่องสัญญาณขาออกเมื่อทำงานเสร็จ - มีเพียงผู้ผลิตเท่านั้นที่ปิดช่องสัญญาณ — ห้ามให้ผู้บริโภคปิด
- ส่งช่องสัญญาณ
done(หรือบริบท) เพื่อยกเลิกการทำงาน - ใช้ชนิดช่องสัญญาณแบบระบุทิศทางในลายเซ็นของฟังก์ชันทั้งหมด
- อ่านค่าที่ค้างอยู่ในช่องสัญญาณเมื่อยกเลิก เพื่อป้องกันโกโรทีนรั่วไหล
ไปป์ไลน์ในโลกจริง: การประมวลผล 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ใช้รับข้อมูลเท่านั้น — ระบุเจตนาไว้อย่างชัดเจนและมีความปลอดภัยที่ตรวจสอบได้ขณะคอมไพล์- ไปป์ไลน์: เชื่อมโกโรทีนเป็นลำดับ โดยแต่ละโกโรทีนอ่านจากช่องสัญญาณหนึ่งช่องและเขียนไปยังอีกช่องหนึ่ง
- Fan-out: ช่องสัญญาณขาเข้าเดียว → โกโรทีนหลายตัว
- Fan-in: ช่องสัญญาณหลายช่อง → รวมเป็นช่องเดียว
- ปิดช่องสัญญาณจากฝั่งผู้ส่งเสมอ และใช้ช่องสัญญาณ done เพื่อยกเลิกการทำงาน
คำถามที่พบบ่อย
บทเรียน “ทิศทางแชนเนลและรูปแบบไปป์ไลน์” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “ทิศทางแชนเนลและรูปแบบไปป์ไลน์” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Go Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Go Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “ทิศทางแชนเนลและรูปแบบไปป์ไลน์”
แชนเนลสำหรับอ่านอย่างเดียว เขียนอย่างเดียว และไปป์ไลน์ คุณปฏิบัติ Go Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Go Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Go Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน
บทเรียน “ทิศทางแชนเนลและรูปแบบไปป์ไลน์” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Go Academy นี้ได้ไหม
ได้ บทเรียน Go Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- การเริ่มใช้กอรูทีน
- แชนเนลแบบไม่มีบัฟเฟอร์
- แชนเนลแบบมีบัฟเฟอร์
- ทิศทางแชนเนลและรูปแบบไปป์ไลน์