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

แชนเนลแบบไม่มีบัฟเฟอร์

ส่งต่อข้อมูลระหว่างกอรูทีนแบบซิงโครนัส

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

ช่องสัญญาณคืออะไร

ช่องสัญญาณ คือช่องทางที่มีชนิดข้อมูลกำกับสำหรับสื่อสารระหว่าง goroutine ช่องสัญญาณเป็นไปตามคติของ Go ที่ว่า อย่าสื่อสารด้วยการแบ่งปันหน่วยความจำ แต่ให้แบ่งปันหน่วยความจำด้วยการสื่อสาร

package main
import "fmt"

func main() {
    ch := make(chan int)   // unbuffered int channel

    go func() {
        ch <- 42  // send: blocks until someone receives
    }()

    v := <-ch  // receive: blocks until someone sends
    fmt.Println(v) // 42
}

ความหมายของช่องสัญญาณไม่มีบัฟเฟอร์

ช่องสัญญาณไม่มีบัฟเฟอร์ไม่มีความจุ การส่งจะถูกบล็อกจนกว่าจะมี receiver พร้อมรับ และการรับจะถูกบล็อกจนกว่า sender จะส่งค่า การทำงานนี้ทำให้เกิดการส่งต่อแบบซิงโครนัสที่รับประกันได้:

package main
import "fmt"

func double(in <-chan int, out chan<- int) {
    for v := range in {
        out <- v * 2
    }
    close(out)
}

func main() {
    in := make(chan int)
    out := make(chan int)
    go double(in, out)
    go func() { in <- 3; in <- 5; close(in) }()
    for v := range out { fmt.Println(v) }
    // 6
    // 10
}

ช่องสัญญาณในฐานะการซิงโครไนซ์

ช่องสัญญาณไม่มีบัฟเฟอร์ใช้ซิงโครไนซ์ goroutine ได้ โดยใช้เป็นสัญญาณว่างานเสร็จแล้ว:

package main
import "fmt"

func compute(result chan<- int) {
    sum := 0
    for i := 1; i <= 100; i++ { sum += i }
    result <- sum
}

func main() {
    ch := make(chan int)
    go compute(ch)
    fmt.Println("Result:", <-ch) // blocks until compute sends
}

การปิดช่องสัญญาณ

sender ปิดช่องสัญญาณด้วย close(ch) เพื่อส่งสัญญาณว่าจะไม่มีการส่งค่าเพิ่มเติม receiver ตรวจพบการปิดได้ผ่านรูปแบบสองค่า:

package main
import "fmt"

func generate(ch chan<- int, max int) {
    for i := 0; i < max; i++ {
        ch <- i
    }
    close(ch)  // signal done
}

func main() {
    ch := make(chan int)
    go generate(ch, 5)

    for v := range ch {  // range detects close automatically
        fmt.Println(v)
    }
    fmt.Println("channel closed")
}

การรับค่าแบบสองค่า

การรับค่าแบบสองค่า v, ok := <-ch ช่วยบอกว่าช่องสัญญาณยังเปิดอยู่หรือไม่:

package main
import "fmt"

func main() {
    ch := make(chan string, 1)
    ch <- "hello"
    close(ch)

    v1, ok1 := <-ch
    fmt.Println(v1, ok1)  // hello true

    v2, ok2 := <-ch
    fmt.Println(v2, ok2)  // "" false — channel closed
}

การส่งไปยังช่องสัญญาณที่ปิดแล้วทำให้เกิดการแพนิก

การส่งค่าไปยังช่องสัญญาณที่ปิดแล้วจะทำให้เกิดการแพนิก เฉพาะ sender เท่านั้นที่ควรปิดช่องสัญญาณ — ห้ามให้ receiver ปิด:

package main
import "fmt"

func main() {
    ch := make(chan int)
    close(ch)

    // Receiving from closed channel returns zero value
    v, ok := <-ch
    fmt.Println(v, ok)  // 0 false

    // Sending to closed channel panics:
    defer func() { recover() }()
    ch <- 1  // panic: send on closed channel
}

ช่องสัญญาณแบบกำหนดทิศทาง

จำกัดช่องสัญญาณให้ส่งได้อย่างเดียว (chan<- T) หรือรับได้อย่างเดียว (<-chan T) ในลายเซ็นฟังก์ชัน เพื่อให้ชัดเจนและปลอดภัย:

package main
import "fmt"

func producer(out chan<- int) {  // send-only
    for i := 0; i < 3; i++ { out <- i }
    close(out)
}

func consumer(in <-chan int) {   // receive-only
    for v := range in { fmt.Println(v) }
}

func main() {
    ch := make(chan int)
    go producer(ch)
    consumer(ch)
}

ปิงปองระหว่าง goroutine และช่องสัญญาณ

goroutine สองรายการส่งข้อความไปมาผ่านช่องสัญญาณ ซึ่งเป็นตัวอย่างคลาสสิกของการซิงโครไนซ์:

package main
import "fmt"

func ping(ping, pong chan struct{}) {
    for i := 0; i < 3; i++ {
        <-ping
        fmt.Println("ping")
        pong <- struct{}{}
    }
}

func main() {
    ping := make(chan struct{})
    pong := make(chan struct{})
    go func() { for { <-pong; fmt.Println("pong"); ping <- struct{}{} } }()
    go func() { for i := 0; i < 3; i++ { ping <- struct{}{}; <-pong } }()
    // Simplified version:
    fmt.Println("channels enable structured communication")
}

ช่องสัญญาณ nil จะบล็อกตลอดไป

การรับจากหรือส่งไปยังช่องสัญญาณ nil จะถูกบล็อกตลอดไป บางครั้งจึงมีการใช้งานลักษณะนี้โดยตั้งใจในคำสั่ง select:

package main
import "fmt"

func main() {
    var ch chan int  // nil channel
    fmt.Println(ch == nil) // true

    // select with nil channel — that case is never selected
    active := make(chan int, 1)
    active <- 42
    select {
    case v := <-ch:      // never selected (nil)
        fmt.Println(v)
    case v := <-active:  // selected
        fmt.Println("got:", v)
    }
}

ควรใช้ช่องสัญญาณไม่มีบัฟเฟอร์เมื่อใด

ใช้ช่องสัญญาณไม่มีบัฟเฟอร์เมื่อ:

  • ต้องการการส่งต่อแบบซิงโครนัสที่รับประกันได้
  • goroutine ต้องยืนยันการรับค่าก่อนที่ sender จะทำงานต่อ
  • กำลังใช้งานเซมาฟอร์หรือการควบคุมการไหลย้อนกลับ
  • กำลังสร้างไปป์ไลน์ที่แต่ละขั้นควรประมวลผลครั้งละหนึ่งรายการ

ตรวจสอบความเข้าใจ

จะเกิดอะไรขึ้นเมื่อส่งค่าไปยังช่องสัญญาณไม่มีบัฟเฟอร์ที่ยังไม่มี receiver พร้อมรับ

ทบทวน: ช่องสัญญาณไม่มีบัฟเฟอร์

สรุป:

  • สร้างด้วย make(chan T) — มีความจุเป็นศูนย์
  • การส่งจะถูกบล็อกจนกว่า receiver จะพร้อม และการรับจะถูกบล็อกจนกว่า sender จะส่ง
  • เฉพาะ sender เท่านั้นที่ควรปิดช่องสัญญาณ
  • range ch วนซ้ำจนกว่าช่องสัญญาณจะถูกปิด
  • การรับค่าแบบสองค่า: v, ok := <-ch
  • ใช้ชนิดข้อมูลแบบกำหนดทิศทางเพื่อความชัดเจน: chan<- และ <-chan

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

บทเรียน “แชนเนลแบบไม่มีบัฟเฟอร์” ฟรีหรือไม่

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

คุณจะเรียนรู้อะไรในบทเรียน “แชนเนลแบบไม่มีบัฟเฟอร์”

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

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

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

บทเรียน “แชนเนลแบบไม่มีบัฟเฟอร์” ใช้เวลานานแค่ไหน

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

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

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

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

  1. การเริ่มใช้กอรูทีน
  2. แชนเนลแบบไม่มีบัฟเฟอร์
  3. แชนเนลแบบมีบัฟเฟอร์
  4. ทิศทางแชนเนลและรูปแบบไปป์ไลน์
← กลับไปที่ Go Academy