Golang并发问题使用无缓冲通道

时间:2018-04-17 09:55:39

标签: go concurrency channel goroutine

我最近开始使用golang编程。 我在golang中创建了一个可以使用golang并发来强制子域的工具。问题是它只显示了前几个结果。我的意思是如果我指定的线程是10,它显示10,如果100,那么它显示100.任何解决方案。我正在关注this示例。

func CheckWildcardSubdomain(state *State, domain string, words <-chan string, wg *sync.WaitGroup) {
    defer wg.Done()

    for {
        preparedSubdomain := <-words + "." + domain
        ipAddress, err := net.LookupHost(preparedSubdomain)

        if err == nil {
            if !state.WildcardIPs.ContainsAny(ipAddress) {
                if state.Verbose == true {
                    fmt.Printf("\n%s", preparedSubdomain)
                }

                state.FinalResults = append(state.FinalResults, preparedSubdomain)
            }
        }
    }
}

func RemoveWildcardSubdomains(state *State, subdomains []string) []string {
    var wg sync.WaitGroup
    var channel = make(chan string)

    wg.Add(state.Threads)

    for i := 0; i < state.Threads; i++ {
        go CheckWildcardSubdomain(state, state.Domain, channel, &wg)
    }

    for _, entry := range subdomains {
        sub := strings.Join(strings.Split(entry, ".")[:2][:], ".")
        channel <- sub
    }

    close(channel)
    wg.Wait()

    return state.FinalResults
}

提前感谢您的帮助。

1 个答案:

答案 0 :(得分:4)

立即脱颖而出的2个错误。

首先,在CheckWildcardSubdomain()中,您应该在words频道上进行搜索:

for word := range words {
    preparedSubdomain := word + "." + domain
    // ...
}

一旦收到通道上发送的所有值(在通道关闭之前发送),通道上的for ... range将终止。请注意,如果通道关闭,简单receive operator将不会终止也不会发生混乱,而是会产生通道元素类型的零值。所以你的原始循环永远不会终止。 Spec: Receive operator:

  

closed频道上的接收操作始终可以立即进行,在收到任何先前发送的值后,会产生元素类型zero value

其次,在CheckWildcardSubdomain()内,state.FinalResults字段被同时读取/修改,没有同步。这是未定义的行为。

您必须同步对此字段的访问权限,例如使用互斥锁,或者您应该找到其他方式来进行通信和收集结果,例如:使用频道。

请参阅此相关问题,以获得优雅,高效和可靠的方法:

Is this an idiomatic worker thread pool in Go?