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

Golang Worker Pool无结果返回问题排查求助

问题分析与修复

你的代码出现了死锁,导致控制台没有任何输出,核心原因是results通道的缓冲限制和接收逻辑的阻塞问题:

  1. 死锁成因:
    • results通道的缓冲只有100,当100个worker都向通道发送了结果后,缓冲被填满
    • 后续worker执行results <- ...时会被阻塞,无法继续处理ports通道里的剩余端口
    • main函数的接收循环需要等待65535条结果才能结束,此时所有worker都卡在发送结果的操作上,main也卡在接收结果的操作上,形成循环阻塞

修复方案(使用WaitGroup优化)

下面是调整后的代码,通过sync.WaitGroup跟踪worker状态,配合异步接收结果的逻辑解决死锁:

package main

import (
    "fmt"
    "net"
    "sync"
)

func worker(ports <-chan int, results chan<- string, wg *sync.WaitGroup) {
    defer wg.Done() // worker完成时标记WaitGroup计数减一
    for p := range ports {
        address := fmt.Sprintf("127.0.0.1:%d", p)
        conn, err := net.Dial("tcp", address)
        if err != nil {
            results <- fmt.Sprintf("Port %d is closed: %s", p, err.Error())
        } else {
            conn.Close()
            results <- fmt.Sprintf("Port %d is open", p)
        }
    }
}

func main() {
    ports := make(chan int, 100)
    results := make(chan string) // 改为无缓冲通道,避免缓冲限制问题
    var wg sync.WaitGroup

    workerCount := cap(ports)
    wg.Add(workerCount)
    // 启动指定数量的worker
    for i := 0; i < workerCount; i++ {
        go worker(ports, results, &wg)
    }

    // 异步发送所有端口号,避免阻塞main
    go func() {
        for j := 1; j <= 65535; j++ {
            ports <- j
        }
        close(ports) // 端口发送完毕,关闭ports通道
        wg.Wait()    // 等待所有worker处理完所有端口
        close(results) // 所有结果发送完毕,关闭results通道
    }()

    // 遍历results通道,实时输出结果,直到通道关闭
    for res := range results {
        fmt.Println(res)
    }
}

关键修改点说明

  • sync.WaitGroup:用于跟踪所有worker的执行状态,确保所有端口处理完成后再关闭results通道
  • 异步发送端口:将端口发送逻辑放到单独的goroutine中,避免main被阻塞
  • 无缓冲results通道:配合实时接收的for range循环,避免缓冲满导致的worker阻塞
  • 通道关闭时机:在所有worker处理完成后关闭results,让main的接收循环自动终止

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 08:53:20