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

自定义Channel Timeout失效触发死锁?如何实现time.After功能

自定义Channel Timeout的死锁问题与修复方案

问题背景

目标是模拟time.After实现Channel超时逻辑,预期代码逻辑如下:

select {
case v := <-c:
    fmt.Println("Value v: ", v)
case <-time.After(1 * time.Second):
    fmt.Println("Timeout")
}

但自行实现的代码运行时报错all goroutines are asleep - deadlock!,代码如下:

func waitFun(wait int) chan int {
    time.Sleep(time.Duration(wait) * time.Second)

    c := make(chan int)
    c <- wait

    return c
}

func main() {
    c := make(chan int)
    go func() {
        time.Sleep(3 * time.Second)
        c <- 10
    }()

    select {
    case v := <-c:
        fmt.Println("Value v: ", v)
    case <-waitFun(1):
        fmt.Println("Timeout")
    }

    time.Sleep(4 * time.Second)
}

死锁原因

你的代码死锁核心问题出在waitFun的执行逻辑:

  • waitFun是在主协程中同步执行的:主协程调用waitFun后,先执行time.Sleep(1*time.Second),休眠结束后创建无缓冲通道c,然后执行c <- wait。
  • 无缓冲通道的发送操作必须有对应的接收操作才能完成,此时主协程还没进入select的接收逻辑,没有任何协程会接收这个新创建的通道数据,导致c <- wait永久阻塞主协程。
  • 同时,匿名协程还在执行time.Sleep(3*time.Second),处于休眠状态。此时所有goroutine都处于阻塞/休眠状态,Go runtime检测到这种情况,触发死锁报错。

对比time.After的实现逻辑:它会启动一个新的后台协程执行休眠,休眠结束后再往通道发送数据,不会阻塞调用它的主协程,主协程可以正常进入select等待通道事件。

修复方案

修改waitFun,让休眠和通道发送逻辑在新协程中执行,确保waitFun能立刻返回通道,主协程可以进入select等待:

修复后的代码

import (
    "fmt"
    "time"
)

func waitFun(wait int) chan int {
    c := make(chan int)
    // 启动新协程执行休眠和发送操作
    go func() {
        time.Sleep(time.Duration(wait) * time.Second)
        c <- wait
    }()
    return c
}

func main() {
    c := make(chan int)
    go func() {
        time.Sleep(3 * time.Second)
        c <- 10
    }()

    select {
    case v := <-c:
        fmt.Println("Value v: ", v)
    case <-waitFun(1):
        fmt.Println("Timeout")
    }

    time.Sleep(4 * time.Second)
}

优化建议(可选)

可以使用带缓冲的通道,避免因select未接收通道数据导致协程阻塞泄漏:

func waitFun(wait int) chan int {
    // 创建缓冲为1的通道
    c := make(chan int, 1)
    go func() {
        time.Sleep(time.Duration(wait) * time.Second)
        c <- wait
    }()
    return c
}

缓冲通道的发送操作无需等待接收即可完成,即使主协程已经从其他通道获取数据,这个后台协程也能正常退出,不会残留阻塞的协程。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 15:50:38