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

การเริ่มใช้กอรูทีน

คีย์เวิร์ด go วงจรชีวิตกอรูทีน และ WaitGroups

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

goroutine คืออะไร

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

  • เริ่มทำงานด้วยคีย์เวิร์ด go
  • สแตกเริ่มต้นประมาณ 2KB (ขยายได้แบบไดนามิก)
  • จัดตารางการทำงานโดยระบบรันไทม์ของ Go ไม่ใช่ OS
  • สื่อสารกันผ่านช่องสัญญาณ ไม่ใช่หน่วยความจำร่วม

คีย์เวิร์ด go

เติม go หน้าการเรียกใช้ฟังก์ชันใดก็ได้เพื่อเปิดใช้งานฟังก์ชันนั้นเป็น goroutine:

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

func greet(name string) {
    fmt.Printf("Hello, %s!\n", name)
}

func main() {
    go greet("Alice")   // runs concurrently
    go greet("Bob")     // runs concurrently
    time.Sleep(100 * time.Millisecond) // wait for goroutines
    fmt.Println("done")
}

วงจรชีวิตของ goroutine

goroutine เริ่มทำงานเมื่อคำสั่ง go ทำงาน และสิ้นสุดเมื่อฟังก์ชันของมันส่งคืนค่า หาก main ส่งคืนค่า goroutine ทั้งหมดจะถูกยุติ:

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

func worker(id int) {
    fmt.Printf("Worker %d starting\n", id)
    time.Sleep(time.Duration(id) * 50 * time.Millisecond)
    fmt.Printf("Worker %d done\n", id)
}

func main() {
    for i := 1; i <= 3; i++ {
        go worker(i)
    }
    time.Sleep(300 * time.Millisecond) // naive wait
}

sync.WaitGroup สำหรับประสานงาน

ใช้ sync.WaitGroup แทนการหยุดรอด้วย sleep เพื่อรอให้ goroutine ทำงานเสร็จ:

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

func worker(id int, wg *sync.WaitGroup) {
    defer wg.Done()  // signal completion
    fmt.Printf("Worker %d working\n", id)
}

func main() {
    var wg sync.WaitGroup
    for i := 1; i <= 5; i++ {
        wg.Add(1)           // register one goroutine
        go worker(i, &wg)
    }
    wg.Wait()               // block until all Done()
    fmt.Println("all workers finished")
}

goroutine แบบไม่ระบุชื่อ

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

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

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 3; i++ {
        i := i  // capture loop variable
        wg.Add(1)
        go func() {
            defer wg.Done()
            fmt.Printf("goroutine %d\n", i)
        }()
    }
    wg.Wait()
}

ข้อควรระวังในการจับค่าตัวแปรลูป

หากไม่จับค่าตัวแปรลูปไว้ goroutine ทั้งหมดอาจเห็นค่าเดียวกัน ซึ่งมักเป็นค่าท้ายสุด นี่เป็นข้อผิดพลาดด้านการทำงานพร้อมกันแบบคลาสสิกใน Go:

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

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 3; i++ {
        wg.Add(1)
        go func(n int) {  // pass i as argument — safe
            defer wg.Done()
            fmt.Println(n)  // prints 0, 1, 2 in some order
        }(i)
    }
    wg.Wait()
}

goroutine เทียบกับเธรด

เหตุผลที่นิยมใช้ goroutine มากกว่าเธรดของ OS:

  • สแตกเริ่มต้น 2KB เทียบกับประมาณ 1MB สำหรับเธรดของ OS
  • ใช้เวลาสร้างระดับไมโครวินาที เทียบกับระดับมิลลิวินาที
  • ระบบรันไทม์ของ Go จัดสรร goroutine หลายรายการให้ทำงานบนเธรดของ OS ตามค่า GOMAXPROCS
  • การสลับ goroutine เป็นแบบร่วมมือกัน จึงไม่ต้องผ่านเคอร์เนล
  • Go จัดการการจัดตารางการทำงานให้ คุณจึงมุ่งเน้นที่ตรรกะได้

GOMAXPROCS

runtime.GOMAXPROCS ควบคุมจำนวนเธรดของ OS ที่ใช้รัน goroutine พร้อมกัน (ค่าเริ่มต้นคือจำนวน CPU):

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

func main() {
    // Default: number of available CPU cores
    fmt.Println("CPUs:", runtime.NumCPU())
    fmt.Println("GOMAXPROCS:", runtime.GOMAXPROCS(0)) // 0 = query without changing

    // Set to 1 for debugging race conditions:
    // runtime.GOMAXPROCS(1)

    fmt.Println("Goroutines:", runtime.NumGoroutine())
}

การรั่วไหลของ goroutine

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

package main
import ("fmt"; "time"; "runtime")

func leaky() {
    ch := make(chan int)  // nobody sends to ch
    go func() {
        v := <-ch  // blocks forever — goroutine leaked!
        fmt.Println(v)
    }()
}

func main() {
    leaky()
    time.Sleep(10 * time.Millisecond)
    fmt.Println("goroutines:", runtime.NumGoroutine()) // > 1
}

แนวทางปฏิบัติที่ดีสำหรับ goroutine

แนวทางสำหรับ goroutine:

  • ต้องทราบเสมอว่า goroutine จะสิ้นสุดการทำงานอย่างไร
  • ใช้ WaitGroup หรือช่องสัญญาณเพื่อซิงโครไนซ์ ไม่ใช่ sleep
  • ส่งตัวแปรลูปเป็นอาร์กิวเมนต์ของฟังก์ชัน ไม่ใช่ส่งผ่านคลอเชอร์
  • ยกเลิก goroutine ด้วย context อย่าปล่อยให้ทำงานต่อไปโดยไม่จำเป็น
  • ใช้ตัวตรวจจับสภาวะแข่งขัน: go run -race main.go

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

วิธีที่ถูกต้องในการหลีกเลี่ยงข้อผิดพลาดจากการจับค่าตัวแปรลูปใน goroutine คืออะไร

ทบทวน: การเปิดใช้งาน goroutine

สรุป:

  • เปิดใช้งานด้วย go fn() — น้ำหนักเบาและมีต้นทุนต่ำ
  • ใช้ sync.WaitGroup เพื่อรอ: Add(1), defer Done(), Wait()
  • จับค่าตัวแปรลูปด้วยอาร์กิวเมนต์หรือการประกาศตัวแปรใหม่
  • ต้องทราบเสมอว่า goroutine แต่ละรายการสิ้นสุดอย่างไร เพื่อป้องกันการรั่วไหล
  • ใช้แฟล็ก -race เพื่อตรวจจับการแข่งขันของข้อมูล

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

บทเรียน “การเริ่มใช้กอรูทีน” ฟรีหรือไม่

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

คุณจะเรียนรู้อะไรในบทเรียน “การเริ่มใช้กอรูทีน”

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

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

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

บทเรียน “การเริ่มใช้กอรูทีน” ใช้เวลานานแค่ไหน

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

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

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

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

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