Go Academy · บทเรียน

การหมดเวลาและตัวนับช่วงเวลา

ใช้ time.After และ time.Tick ร่วมกับ select

บทเรียน 2 จาก 413 ขั้นตอน

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

เหตุใดการกำหนดเวลาสิ้นสุดจึงสำคัญ

หากไม่มีการกำหนดเวลาสิ้นสุด โกโรทีนที่รอช่องสัญญาณทำงานช้าอาจถูกบล็อกตลอดไป แพ็กเกจ time มีเครื่องมือพื้นฐานสำหรับเพิ่มการควบคุมตามเวลาให้กับการดำเนินการกับช่องสัญญาณ

time.After สำหรับการกำหนดเวลาสิ้นสุดครั้งเดียว

time.After(d) คืนช่องสัญญาณที่รับค่าได้หลังผ่านระยะเวลา d ใช้ใน case ของ select เพื่อยกเลิกการรอ

select {
case res := <-ch:
    fmt.Println(res)
case <-time.After(2 * time.Second):
    fmt.Println("timed out")
}

การกำหนดเวลาซ้ำด้วย time.NewTimer

สำหรับตัวจับเวลาที่นำกลับมาใช้ซ้ำได้ ให้ใช้ time.NewTimer และเรียก Reset หลังการใช้งานแต่ละครั้ง เรียก Stop เพื่อป้องกันโกโรทีนของตัวจับเวลารั่วไหล

timer := time.NewTimer(5 * time.Second)
defer timer.Stop()
select {
case <-timer.C:
    fmt.Println("timer fired")
}

time.Tick เทียบกับ time.NewTicker

time.Tick สะดวกในการใช้งาน แต่ทำให้ ticker ที่อยู่เบื้องหลังรั่วไหล — ควรใช้ time.NewTicker เพื่อให้เรียก Stop() และคืนทรัพยากรได้

ticker := time.NewTicker(500 * time.Millisecond)
defer ticker.Stop()
for range ticker.C {
    fmt.Println("tick")
}

Ticker ในลูป

ใช้ ticker ร่วมกับช่องสัญญาณ done เพื่อขับเคลื่อนงานที่ทำเป็นระยะและหยุดได้อย่างเรียบร้อย

ticker := time.NewTicker(time.Second)
done := make(chan struct{})
go func() {
    for {
        select {
        case <-ticker.C:
            doWork()
        case <-done:
            ticker.Stop()
            return
        }
    }
}()

การรั่วไหลจาก time.After

time.After สร้างตัวจับเวลาใหม่ทุกครั้งที่เรียกใช้ และตัวจับเวลาจะถูกเก็บคืนโดยตัวเก็บขยะไม่ได้จนกว่าจะทำงาน เมื่อใช้ในลูปที่ทำงานถี่ ควรใช้ time.NewTimer + Reset เพื่อหลีกเลี่ยงตัวจับเวลารั่วไหล

กำหนดเวลาสิ้นสุดเทียบกับเวลาหมด

เวลาหมดเป็นระยะเวลาสัมพัทธ์ ("รอ 5 วินาที") ส่วนกำหนดเวลาสิ้นสุดเป็นเวลาที่แน่นอน ("รอจนถึง 14:00 น.") ใช้ time.Until(deadline) เพื่อแปลงกำหนดเวลาสิ้นสุดเป็นระยะเวลาสำหรับ time.After

deadline := time.Now().Add(5 * time.Second)
select {
case v := <-ch:
    use(v)
case <-time.After(time.Until(deadline)):
    fmt.Println("deadline exceeded")
}

ควรใช้ context.WithTimeout

สำหรับตัวจัดการ HTTP และงานที่มีโครงสร้าง ควรใช้ context.WithTimeout แทนการกำหนดเวลาหมดด้วยช่องสัญญาณโดยตรง เพราะจะส่งต่อการยกเลิกไปตามลำดับการเรียกฟังก์ชันโดยอัตโนมัติ

ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()

การจำกัดอัตราด้วย Ticker

ticker เป็นตัวจำกัดอัตราที่ง่ายที่สุด: ส่งคำขอหนึ่งรายการต่อหนึ่งจังหวะ หากต้องการรองรับการส่งเป็นชุด ให้เติมค่าลงในช่องสัญญาณแบบมีบัฟเฟอร์ไว้ล่วงหน้า แล้วเติมค่าเพิ่มด้วย ticker

requests := make(chan int, 5)
for i := 0; i < 5; i++ { requests <- i }
close(requests)
limiter := time.NewTicker(200 * time.Millisecond)
for req := range requests {
    <-limiter.C
    fmt.Println("request", req)
}

นาฬิกาแบบโมโนโทนิก

ระยะเวลาของตัวจับเวลาใน Go ใช้นาฬิกาแบบโมโนโทนิก ไม่ใช่นาฬิกาตามเวลาจริง จึงไม่ได้รับผลกระทบจากการปรับนาฬิกาของระบบ time.Since และ time.Until ก็ใช้วิธีนี้เช่นกัน

การหยุด ticker อย่างถูกต้อง

หลังจาก ticker.Stop() ช่องสัญญาณของ ticker จะไม่ถูกปิด — เพียงหยุดรับค่าเท่านั้น หากจำเป็น ให้รับค่าที่ค้างอยู่ในช่องสัญญาณออกก่อนส่งคืน

ตรวจสอบความเข้าใจอย่างรวดเร็ว

เหตุใดจึงควรใช้ time.NewTicker แทน time.Tick

ทบทวน: การกำหนดเวลาสิ้นสุดและ Ticker

ประเด็นสำคัญ:

  • ใช้ time.After สำหรับการกำหนดเวลาสิ้นสุดครั้งเดียวใน select
  • ใช้ time.NewTicker สำหรับงานที่ทำซ้ำ และเรียก Stop() เสมอ
  • หลีกเลี่ยง time.After ในลูป — เพราะทำให้ตัวจับเวลารั่วไหล
  • ควรใช้ context.WithTimeout สำหรับงานที่ยกเลิกได้
เริ่มต้นได้ฟรี

เรียนรู้ Go ด้วย AI tutor — ฟรี

เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป

คอร์ส
51
บทเรียน
203

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

บทเรียน “การหมดเวลาและตัวนับช่วงเวลา” ฟรีหรือไม่

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

คุณจะเรียนรู้อะไรในบทเรียน “การหมดเวลาและตัวนับช่วงเวลา”

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

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

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

บทเรียน “การหมดเวลาและตัวนับช่วงเวลา” ใช้เวลานานแค่ไหน

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

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

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

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

  1. คำสั่ง select
  2. การหมดเวลาและตัวนับช่วงเวลา
  3. รูปแบบ Fan-in และ Fan-out
  4. รูปแบบกลุ่มผู้ทำงาน
← กลับไปที่ Go Academy