You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go语言程序永久阻塞疑问:time.Tick与通道遍历相关咨询

两段Go代码的阻塞/死锁原因分析及疑问确认

第一段永久阻塞的代码

package main

import (
    "fmt"
    "time"
)

func main() {
    burstyLimiter := make(chan time.Time, 3)
    for i := 1; i <= 3; i++ {
        burstyLimiter <- time.Now()
    }

    go func() {
        for t := range time.Tick(200 * time.Millisecond) {
            burstyLimiter <- t
        }
    }()

    burstyRequests := make(chan int, 5)
    for i := 1; i <= 5; i++ {
        burstyRequests <- i
    }
    for r := range burstyRequests {
        fmt.Println("received request", r, time.Now())
    }
}

第二段死锁的代码

package main

import (
    "fmt"
    "time"
)

func main() {
    burstyRequests := make(chan int, 5)
    for i := 1; i <= 5; i++ {
        burstyRequests <- i
    }
    for r := range burstyRequests {
        fmt.Println("received request", r, time.Now())
    }
}

你的疑问确认与原因拆解

你的猜测部分正确,但需要明确两个问题的边界:

  • goroutine泄漏确实存在,但不是main goroutine永久阻塞的直接原因
    后台启动的goroutine通过time.Tick持续向burstyLimiter写入数据,而main函数全程没有读取burstyLimiter的逻辑。由于burstyLimiter是容量为3的缓冲通道,当缓冲被填满后,这个后台goroutine会永久阻塞在burstyLimiter <- t这一行,形成goroutine泄漏,但这个泄漏不会直接导致main goroutine阻塞。

  • main goroutine永久阻塞的真正原因:未关闭通道导致for range遍历持续等待
    两段代码的核心问题都是burstyRequests通道没有被关闭。Go中用for range遍历通道时,只有当通道被显式关闭且缓冲内的元素全部被读取完毕后,遍历才会退出:

    • 第二段代码里,没有其他goroutine会向burstyRequests写入数据,main goroutine读完缓冲的5个元素后就会一直等待新数据,没有退出条件,最终触发死锁;
    • 第一段代码里,main goroutine的阻塞原因和第二段完全一致:burstyRequests未关闭,遍历读完5个元素后持续等待,导致永久阻塞。

简单来说,你提到的goroutine泄漏是第一段代码的额外问题,但不是程序永久阻塞的核心原因;而"通道遍历因未关闭、持续等待新数据而阻塞"才是两段代码出问题的关键。

内容的提问来源于stack exchange,提问作者opensaucerer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 09:05:19