等待所有的例程,非阻塞

时间:2018-04-26 22:42:15

标签: go

我对go例程有疑问。

我的代码:

func main() {

    ok := make(chan bool, 1)

    i := 0
    fmt.Println("Starting...")
    for i <= 3 {
        fmt.Println("Loop: ", i)
        go long(ok, i)
        time.Sleep(1 * time.Second)
        i = i + 1

        select {
        case _ = <-ok:
        default:
            fmt.Println("Default")
        }
    }

    fmt.Println("Done...")

}

func long(c chan bool, i int){
    fmt.Println("Inside long: ", i)
    time.Sleep(3 * time.Second)
    fmt.Println("Done with loop: ", i)
    c <- true

}

这给了我输出:

Starting...
Loop:  0
Inside long:  0
Default
Loop:  1
Inside long:  1
Default
Loop:  2
Inside long:  2
Done with loop:  0
Loop:  3
Inside long:  3
Done with loop:  1
Done...

因为我使用了default中的select,所以该频道是非阻止的。主要功能退出,所有当前例程也退出。然后我阅读了syncWaitGrops

func main() {

    ok := make(chan bool, 1)

    var wg sync.WaitGroup

    i := 0
    fmt.Println("Starting...")
    for i <= 3 {
        fmt.Println("Loop: ", i)
        wg.Add(1)
        go long(ok, i)
        time.Sleep(1 * time.Second)
        i = i + 1

        select {
            case _ = <-ok:
            default:
                fmt.Println("Default")
        }
    }

    wg.Wait()
    fmt.Println("Done...")

}

这给了我:

Starting...
Loop:  0
Inside long:  0
Default
Loop:  1
Inside long:  1
Default
Loop:  2
Inside long:  2
Done with loop:  0
Loop:  3
Inside long:  3
Done with loop:  1
Done with loop:  2
Done with loop:  3

我们现在更接近我期望的执行,即: for循环使所有调用函数,然后我得到结果异步。如果一切顺利的话,这将是美好的。但是会产生错误:

fatal error: all goroutines are asleep - deadlock! 

为什么会这样,我应该如何解决? (是否可以在不知道执行wg.Add()多少次的情况下进行修复?)

3 个答案:

答案 0 :(得分:3)

您需要在def arrayCheck(nums): for i in range(len(nums)-2): if nums[i]==1 and nums[i+1]==2 and nums[i+3]==3: return True return False x=arrayCheck([1, 1, 2, 3, 1]) print(x) 上致电Done(),呼叫WaitGroup,以便Add(1)可以取消阻止。您不再需要频道同步:

wg.Wait()

答案 1 :(得分:1)

所以,比特&#39; answer会删除解决问题的渠道。

频道出现问题的原因是你的goroutines试图写入三次,缓冲区大小为1。并且您的主程序很快就会删除三个goroutine,并且由于select中的默认值而从不等待读取通道。因此它永远不会被读取,并且goroutines无法写入它。

答案 2 :(得分:0)

您也可以使用频道执行此操作,但它不如WaitGroup那么优雅,因为它需要更多的同步工作。

对于上述问题,您可以执行以下操作:

package main

func main() {

    ok := make(chan bool, 1)
    done := make(chan bool)

    i := 0
    j := 0
    fmt.Println("Starting...")
    for i <= 3 {
        fmt.Println("Loop: ", i)
        go long(ok, i)
        time.Sleep(1 * time.Second)
        i = i + 1
    }

    go func() {

        for {
            select {
            case _ = <-ok:
                j++
                if j == 4 {
                    done <- true
                    return
                }
            }
        }
    }()

    <-done
    fmt.Println("Done...")

}

func long(c chan bool, i int) {
    fmt.Println("Inside long: ", i)
    time.Sleep(3 * time.Second)
    fmt.Println("Done with loop: ", i)
    c <- true

}