การเริ่มใช้กอรูทีน
คีย์เวิร์ด 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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- การเริ่มใช้กอรูทีน
- แชนเนลแบบไม่มีบัฟเฟอร์
- แชนเนลแบบมีบัฟเฟอร์
- ทิศทางแชนเนลและรูปแบบไปป์ไลน์