为了账号安全,请及时绑定邮箱和手机立即绑定

需要运行几个 func() 布尔并获取第一个假

需要运行几个 func() 布尔并获取第一个假

Go
青春有我 2022-09-19 10:37:33
我正在尝试优化在IF语句中运行多个函数的验证过程,因此我试图使用go的并发来解决这个问题,但它不起作用。我运行以下代码并尝试了很多不同的方法来实现通道关闭和等待组,但我不断收到以下错误:fatal error: all goroutines are asleep - deadlock!goroutine 1 [chan send]:main.main.func1(0xc000074f60, 0x3, 0x3, 0xc000024180, 0xc0000241e0)        /home/raphael/projects/go/go-herupaa/main.go:24 +0x9fmain.main()        /home/raphael/projects/go/go-herupaa/main.go:25 +0xcbgoroutine 6 [chan send]:main.a1(0xc0000241e0)        /home/raphael/projects/go/go-herupaa/main.go:49 +0x72created by main.main.func1        /home/raphael/projects/go/go-herupaa/main.go:22 +0x71goroutine 7 [chan send]:main.a2(0xc0000241e0)        /home/raphael/projects/go/go-herupaa/main.go:56 +0x72created by main.main.func1        /home/raphael/projects/go/go-herupaa/main.go:22 +0x71goroutine 8 [chan send]:main.a3(0xc0000241e0)        /home/raphael/projects/go/go-herupaa/main.go:63 +0x72created by main.main.func1        /home/raphael/projects/go/go-herupaa/main.go:22 +0x71exit status 2package mainimport (    "fmt"    "sync"    "time")var wg sync.WaitGroupfunc main() {    v := []func(chan<- bool){        a1,        a2,        a3,    }    q := make(chan bool)    c := make(chan bool)    func(c chan bool) {        for _, f := range v {            wg.Add(1)            go f(c)        }        q <- true    }(c)    p := receive(c, q)    fmt.Println(p)    wg.Wait()}func receive(c, q chan bool) bool {    for {        select {        case v := <-c:            if !v {                fmt.Println("Received ", v)                return false            }        case <-q:            fmt.Println("Received Exit")            return true        }    }}func a1(c chan<- bool) {    defer wg.Done()    time.Sleep(time.Millisecond * 2000)    c <- true    fmt.Println("Finish 1")}func a2(c chan<- bool) {    defer wg.Done()    time.Sleep(time.Millisecond * 2000)    c <- true    fmt.Println("Finish 2")}func a3(c chan<- bool) {    defer wg.Done()    time.Sleep(time.Millisecond * 2000)    c <- true    fmt.Println("Finish 3")}去
查看完整描述

2 回答

?
喵喵时光机

TA贡献1846条经验 获得超7个赞

您的第一个问题是:q <- true


func(c chan bool) {

        for _, f := range v {

            wg.Add(1)

            go f(c)

        }

        q <- true

    }(c)

将其包含在块中没有任何作用(我怀疑您在某个时候在go例程中运行它)。正如所写的,它将启动三个去例程,然后击中。由于没有任何东西接收到,这将被阻止。func()q <- trueq


修复后,您将遇到下一个问题:


p := receive(c, q)

fmt.Println(p)

wg.Wait()

receive从 或 中抓取一些东西;您可能希望从中获取三个值,然后从中获取一个值,但它同样可能(可能更有可能)从之前接收(这会导致另一个死锁)。vqvqqvwg.Wait


有几种方法可以解决这个问题;正如彼得在评论中提到的,您可以使用缓冲通道(例如);发送到被阻止的通道不会阻止,除非该通道已满。或者,我怀疑你的意图是这样的(游乐场):c := make(chan bool, len(v))


func main() {

    v := []func(chan<- bool){

        a1,

        a2,

        a3,

    }

    q := make(chan bool)

    c := make(chan bool)


    for _, f := range v {

        wg.Add(1)

        go f(c)

    }

    // When the above go routines have completed send to q

    go func() {

        wg.Wait()

        q <- true

    }()


    p := receive(c, q)

    fmt.Println(p)

}

正如彼得所指出的,你确实需要适应提前接纳和离开的情况。这可以通过使用缓冲通道来解决,或者您可以启动一个go例程,该例程仅转储通道上接收的数据,即:receivefalsev


case v := <-c:

   if !v {

      fmt.Println("Received ", v)

      // Throw away anything else received on v to allow other go routines to complete

      go func() { for _ = range v {}}()

      return false

   }

如果你采取这种方法,你需要确保最终关闭;事实上,你可以用它作为退出的信号,这可以大大简化事情:v


go func() {

        wg.Wait()

        close(c)

    }()

这完全消除了对的需求。您的范围可以通过通道,例如)。qreceivefor v := range c {...


查看完整回答
反对 回复 2022-09-19
?
有只小跳蛙

TA贡献1824条经验 获得超8个赞

这加起来是英国人的伟大而详细的答案。


此示例使用上下文取消来跳过写入,它总是会耗尽 。c


原始代码中的问题是,您试图通过从其出口点停止流来退出,您正在阻碍它。


正如 Brits 的回答所示,这不是停止处理流的正确方法,因为它会在管道中留下非托管数据。


一般的想法是在取消信号到达时停止将数据发送到管道(关闭输入数据源),并让管道通过完全耗尽正在进行的数据来完成其对正在进行的数据的工作。


package main


import (

    "context"

    "fmt"

    "os"

    "os/signal"

    "sync"

    "time"

)


func main() {

    ctx, cancel := context.WithCancel(context.Background())

    go func() {

        s := make(chan os.Signal, 10)

        signal.Notify(s)

        <-s

        cancel()

    }()

    // let us simulate cancellation

    go func() {

        <-time.After(time.Millisecond * 200)

        cancel()

    }()

    v := []func(context.Context, chan<- bool){

        a1,

        a2,

        a3,

    }

    c := make(chan bool)


    var wg sync.WaitGroup

    for _, f := range v {

        wg.Add(1)

        f := f

        go func() {

            f(ctx, c)

            wg.Done()

        }()

    }

    go func() {

        wg.Wait()

        close(c)

    }()


    for v := range c {

        fmt.Println("Received ", v)

    }

}


func a1(ctx context.Context, c chan<- bool) {

    <-time.After(time.Millisecond * 1000)

    select {

    case c <- true:

        fmt.Println("Finish 1")

    case <-ctx.Done():

        fmt.Println("Cancelled 1")

    }

}


func a2(ctx context.Context, c chan<- bool) {

    <-time.After(time.Millisecond * 1000)

    select {

    case c <- true:

        fmt.Println("Finish 2")

    case <-ctx.Done():

        fmt.Println("Cancelled 2")

    }

}


func a3(ctx context.Context, c chan<- bool) {

    <-time.After(time.Millisecond * 1000)

    select {

    case c <- true:

        fmt.Println("Finish 3")

    case <-ctx.Done():

        fmt.Println("Cancelled 3")

    }

}

最后回答问题标题Need to run several func() bool and get the first false


您可能希望实现流减少。捕获所有值,实现一个小逻辑以尽快关闭您的减排目标。但总是继续完全耗尽它。


package main


import (

    "context"

    "fmt"

    "os"

    "os/signal"

    "sync"

    "time"

)


func main() {

    ctx, cancel := context.WithCancel(context.Background())

    go func() {

        s := make(chan os.Signal, 10)

        signal.Notify(s)

        <-s

        cancel()

    }()

    // let us simulate cancellation

    go func() {

        <-time.After(time.Millisecond * 200)

        cancel()

    }()

    v := []func(context.Context, chan<- bool){

        a1,

        a2,

        a3,

    }

    c := make(chan bool)


    var wg sync.WaitGroup

    for _, f := range v {

        wg.Add(1)

        f := f

        go func() {

            f(ctx, c)

            wg.Done()

        }()

    }

    // When the above go routines have completed send to q

    go func() {

        wg.Wait()

        close(c)

    }()


    firstRes := make(chan bool)

    go func() {

        var closed bool

        for v := range c {

            if !v && !closed {

                firstRes <- v

                closed = true

                close(firstRes)

            }

            fmt.Println("Received ", v)

        }

        if !closed {

            close(firstRes)

        }

    }()

    var wasFalsy bool

    for v := range firstRes {

        wasFalsy = !v

    }

    fmt.Println("was falsy ", wasFalsy)

}


func a1(ctx context.Context, c chan<- bool) {

    <-time.After(time.Millisecond * 2000)

    select {

    case c <- !true:

        fmt.Println("Finish 1")

    case <-ctx.Done():

        fmt.Println("Cancelled 1")

    }

}


func a2(ctx context.Context, c chan<- bool) {

    <-time.After(time.Millisecond * 2000)

    select {

    case c <- true:

        fmt.Println("Finish 2")

    case <-ctx.Done():

        fmt.Println("Cancelled 2")

    }

}


func a3(ctx context.Context, c chan<- bool) {

    <-time.After(time.Millisecond * 2000)

    select {

    case c <- true:

        fmt.Println("Finish 3")

    case <-ctx.Done():

        fmt.Println("Cancelled 3")

    }

}


查看完整回答
反对 回复 2022-09-19
  • 2 回答
  • 0 关注
  • 79 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信