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

Go语言使用Select语句时出现死锁的原因及解决办法

Go语言goroutine与select死锁问题分析与解决

死锁原因

你启动了4个统计goroutine,每个只会向对应通道发送一次统计结果,但main函数里的for循环要执行5次select操作:

  • 前4次select会接收完4个通道的所有数据
  • 第5次循环时,所有通道既没有新数据发送,也没被关闭,main goroutine会一直阻塞在select上。此时4个统计goroutine已经执行完毕退出,没有其他活跃的goroutine,Go运行时检测到所有goroutine都休眠,触发死锁错误。

解决方法

1. 修正循环次数为4

最直接的方式是把循环次数改成4,因为只有4个统计结果需要接收:

for i := 0; i < 4; i++ {
    select {
    case t1 := <-letters:
        fmt.Println("letter :", t1)
    case t2 := <-digits:
        fmt.Println("Digits :", t2)
    case t3 := <-others:
        fmt.Println("Others :", t3)
    case t4 := <-spaces:
        fmt.Println("Spaces :", t4)
    }
}

2. 用sync.WaitGroup跟踪goroutine状态

通过WaitGroup等待所有统计goroutine完成后,再处理结果,避免依赖固定循环次数:

import (
    "fmt"
    "sync"
    "unicode"
)

func main() {
    letters := make(chan int)
    digits := make(chan int)
    others := make(chan int)
    spaces := make(chan int)
    var wg sync.WaitGroup

    text := `William Butler Yeats (1865-1939) is one of the greatest of all Irish poets.

No Second Troy

Why should I blame her that she filled my days
With misery, or that she would of late
Have taught to ignorant men most violent ways,
Or hurled the little streets upon the great,
Had they but courage equal to desire?
What could have made her peaceful with a mind
That nobleness made simple as a fire,
With beauty like a tightened bow, a kind
That is not natural in an age like this,
Being high and solitary and most stern?
Why, what could she have done, being what she is?
Was there another Troy for her to burn?`

    // 给每个goroutine添加等待计数
    wg.Add(4)
    go func() {
        defer wg.Done()
        cntLetters(text, letters)
    }()
    go func() {
        defer wg.Done()
        cntDigits(text, digits)
    }()
    go func() {
        defer wg.Done()
        cntOthers(text, others)
    }()
    go func() {
        defer wg.Done()
        cntSpaces(text, spaces)
    }()

    // 启动goroutine等待所有统计完成后关闭通道
    go func() {
        wg.Wait()
        close(letters)
        close(digits)
        close(others)
        close(spaces)
    }()

    // 接收所有结果,直到通道关闭
    received := 0
    for received < 4 {
        select {
        case t1, ok := <-letters:
            if ok {
                fmt.Println("letter :", t1)
                received++
            }
        case t2, ok := <-digits:
            if ok {
                fmt.Println("Digits :", t2)
                received++
            }
        case t3, ok := <-others:
            if ok {
                fmt.Println("Others :", t3)
                received++
            }
        case t4, ok := <-spaces:
            if ok {
                fmt.Println("Spaces :", t4)
                received++
            }
        }
    }
}

// 以下统计函数保持不变
func cntLetters(txt string, letters chan int) {
    s := 0
    for _, v := range txt {
        if unicode.IsLetter(v) {
            s++
        }
    }
    letters <- s
}

func cntDigits(txt string, digits chan int) {
    s := 0
    for _, v := range txt {
        if unicode.IsDigit(v) {
            s++
        }
    }
    digits <- s
}

func cntOthers(txt string, others chan int) {
    s := 0
    for _, v := range txt {
        if !unicode.IsDigit(v) && !unicode.IsLetter(v) && !unicode.IsSpace(v) {
            s++
        }
    }
    others <- s
}

func cntSpaces(txt string, spaces chan int) {
    s := 0
    for _, v := range txt {
        if unicode.IsSpace(v) {
            s++
        }
    }
    spaces <- s
}

3. 使用统一结果通道

把所有统计结果发送到一个通道,用信号通知main函数所有统计完成:

import (
    "fmt"
    "unicode"
)

type Result struct {
    Type  string
    Count int
}

func main() {
    resultChan := make(chan Result)
    done := make(chan struct{})
    totalWorkers := 4

    text := `William Butler Yeats (1865-1939) is one of the greatest of all Irish poets.

No Second Troy

Why should I blame her that she filled my days
With misery, or that she would of late
Have taught to ignorant men most violent ways,
Or hurled the little streets upon the great,
Had they but courage equal to desire?
What could have made her peaceful with a mind
That nobleness made simple as a fire,
With beauty like a tightened bow, a kind
That is not natural in an age like this,
Being high and solitary and most stern?
Why, what could she have done, being what she is?
Was there another Troy for her to burn?`

    // 字母统计
    go func() {
        s := 0
        for _, v := range text {
            if unicode.IsLetter(v) {
                s++
            }
        }
        resultChan <- Result{Type: "letter", Count: s}
        done <- struct{}{}
    }()

    // 数字统计
    go func() {
        s := 0
        for _, v := range text {
            if unicode.IsDigit(v) {
                s++
            }
        }
        resultChan <- Result{Type: "digit", Count: s}
        done <- struct{}{}
    }()

    // 特殊字符统计
    go func() {
        s := 0
        for _, v := range text {
            if !unicode.IsDigit(v) && !unicode.IsLetter(v) && !unicode.IsSpace(v) {
                s++
            }
        }
        resultChan <- Result{Type: "others", Count: s}
        done <- struct{}{}
    }()

    // 空格统计
    go func() {
        s := 0
        for _, v := range text {
            if unicode.IsSpace(v) {
                s++
            }
        }
        resultChan <- Result{Type: "spaces", Count: s}
        done <- struct{}{}
    }()

    // 等待所有worker完成后关闭结果通道
    go func() {
        for i := 0; i < totalWorkers; i++ {
            <-done
        }
        close(resultChan)
    }()

    // 遍历结果通道输出所有统计
    for res := range resultChan {
        fmt.Printf("%s : %d\n", res.Type, res.Count)
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 12:12:06