所有的 goroutines 都是 sleep deadlock

All goroutines are sleep deadlock

模拟我的真实问题我有这段代码。
基本上,数组“letters”的每个元素及其索引被发送到 goroutine 以将其与“x”进行比较,然后它通过通道发送响应。 我的想法是它在“x”个线程上运行,在实际情况下我使用 8 个线程。

package main

import (
    "strconv"
    "sync"
)

var wg sync.WaitGroup
const sizeLetters = 12

func detectX(ch2 chan int, j int, letters [sizeLetters]string) {
    if letters[j] == "x" {
        ch2 <- j
    }else{
        ch2 <- -1
    }
}


func main() {
    ch1 := make(chan int)
    ch2 := make(chan int)
    letters := [sizeLetters]string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l"}
    threads:= 4
    wg.Add(threads)
    for i := 0; i < threads; i++ {
        go func() {
            for {
                j, ok := <-ch1
                if !ok {
                    wg.Done()
                }
                detectX(ch2, j, letters)
            }
        }()
    }
    for i := 0; i < sizeLetters; i++ {
        ch1<-i // add i to the queue
    }
    k, ok := <-ch2 //k contains the position of X, if exist
    if !ok {
        wg.Done()
    }
    if k != -1 { //when exist
        println("X exist in position: " + strconv.Itoa(k))
    }
    println("X doesn´t exist")
    close(ch2)
    close(ch1)
    wg.Wait()
}

信誉不足,无法发表评论。因此,代替注释,这里是代码的替代版本:

package main

import (
    "fmt"
    "sync"
)

var wg sync.WaitGroup

const sizeLetters = 12

func detectX(ch2 chan int, j int, letters [sizeLetters]string) {
    if letters[j] == "x" {
        ch2 <- j
    }
}

func main() {
    ch1 := make(chan int)
    ch2 := make(chan int)
    letters := [sizeLetters]string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l"}
    threads := 4
    wg.Add(threads)
    for i := 0; i < threads; i++ {
        go func() {
            for {
                j, ok := <-ch1
                if !ok {
                    wg.Done()
                    return
                }
                detectX(ch2, j, letters)
            }
        }()
    }
    // Use a goroutine to close ch2. It is only safe to do this
    // after all the other goroutines have exited.
    go func() {
        wg.Wait()
        close(ch2)
    }()
    for i := 0; i < sizeLetters; i++ {
        ch1 <- i // add i to the queue
    }
    close(ch1)
    if k, ok := <-ch2; ok && k != -1 { //when exist
        fmt.Println("X exist in position:", k)
    } else {
        fmt.Println("X doesn´t exist")
    }
}

它仍然存在一些数据相关问题(除非保证 letters 数组不包含重复项):

  • 即如果数组中有多个"x",goroutines不会全部退出。即main()不漏ch2.
  • 如果有 threads "x" 个值,那么代码将死锁在 main() 的顶层 for 循环中,因为写入 ch1 将从未阻塞的 goroutines 中 运行 消耗它们。
    • 如果您知道 letters 数组中可能有多少 "x" 个值,您可以使 ch2 通道那么深:ch2 := make(chan int, depth)。这将允许所有 goroutines 退出,但 ch2 可能仍包含未耗尽的数据。