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

我正在尝试优化在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 +0x9f

main.main()

        /home/raphael/projects/go/go-herupaa/main.go:25 +0xcb


goroutine 6 [chan send]:

main.a1(0xc0000241e0)

        /home/raphael/projects/go/go-herupaa/main.go:49 +0x72

created by main.main.func1

        /home/raphael/projects/go/go-herupaa/main.go:22 +0x71


goroutine 7 [chan send]:

main.a2(0xc0000241e0)

        /home/raphael/projects/go/go-herupaa/main.go:56 +0x72

created by main.main.func1

        /home/raphael/projects/go/go-herupaa/main.go:22 +0x71


goroutine 8 [chan send]:

main.a3(0xc0000241e0)

        /home/raphael/projects/go/go-herupaa/main.go:63 +0x72

created by main.main.func1

        /home/raphael/projects/go/go-herupaa/main.go:22 +0x71

exit status 2

package main


import (

    "fmt"

    "sync"

    "time"

)


var wg sync.WaitGroup


func 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")

}


青春有我
浏览 108回答 2
2回答

喵喵时光机

您的第一个问题是:q <- truefunc(c chan bool) {&nbsp; &nbsp; &nbsp; &nbsp; for _, f := range v {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; wg.Add(1)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; go f(c)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; q <- true&nbsp; &nbsp; }(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() {&nbsp; &nbsp; v := []func(chan<- bool){&nbsp; &nbsp; &nbsp; &nbsp; a1,&nbsp; &nbsp; &nbsp; &nbsp; a2,&nbsp; &nbsp; &nbsp; &nbsp; a3,&nbsp; &nbsp; }&nbsp; &nbsp; q := make(chan bool)&nbsp; &nbsp; c := make(chan bool)&nbsp; &nbsp; for _, f := range v {&nbsp; &nbsp; &nbsp; &nbsp; wg.Add(1)&nbsp; &nbsp; &nbsp; &nbsp; go f(c)&nbsp; &nbsp; }&nbsp; &nbsp; // When the above go routines have completed send to q&nbsp; &nbsp; go func() {&nbsp; &nbsp; &nbsp; &nbsp; wg.Wait()&nbsp; &nbsp; &nbsp; &nbsp; q <- true&nbsp; &nbsp; }()&nbsp; &nbsp; p := receive(c, q)&nbsp; &nbsp; fmt.Println(p)}正如彼得所指出的,你确实需要适应提前接纳和离开的情况。这可以通过使用缓冲通道来解决,或者您可以启动一个go例程,该例程仅转储通道上接收的数据,即:receivefalsevcase v := <-c:&nbsp; &nbsp;if !v {&nbsp; &nbsp; &nbsp; fmt.Println("Received ", v)&nbsp; &nbsp; &nbsp; // Throw away anything else received on v to allow other go routines to complete&nbsp; &nbsp; &nbsp; go func() { for _ = range v {}}()&nbsp; &nbsp; &nbsp; return false&nbsp; &nbsp;}如果你采取这种方法,你需要确保最终关闭;事实上,你可以用它作为退出的信号,这可以大大简化事情:vgo func() {&nbsp; &nbsp; &nbsp; &nbsp; wg.Wait()&nbsp; &nbsp; &nbsp; &nbsp; close(c)&nbsp; &nbsp; }()这完全消除了对的需求。您的范围可以通过通道,例如)。qreceivefor v := range c {...

有只小跳蛙

这加起来是英国人的伟大而详细的答案。此示例使用上下文取消来跳过写入,它总是会耗尽 。c原始代码中的问题是,您试图通过从其出口点停止流来退出,您正在阻碍它。正如 Brits 的回答所示,这不是停止处理流的正确方法,因为它会在管道中留下非托管数据。一般的想法是在取消信号到达时停止将数据发送到管道(关闭输入数据源),并让管道通过完全耗尽正在进行的数据来完成其对正在进行的数据的工作。package mainimport (&nbsp; &nbsp; "context"&nbsp; &nbsp; "fmt"&nbsp; &nbsp; "os"&nbsp; &nbsp; "os/signal"&nbsp; &nbsp; "sync"&nbsp; &nbsp; "time")func main() {&nbsp; &nbsp; ctx, cancel := context.WithCancel(context.Background())&nbsp; &nbsp; go func() {&nbsp; &nbsp; &nbsp; &nbsp; s := make(chan os.Signal, 10)&nbsp; &nbsp; &nbsp; &nbsp; signal.Notify(s)&nbsp; &nbsp; &nbsp; &nbsp; <-s&nbsp; &nbsp; &nbsp; &nbsp; cancel()&nbsp; &nbsp; }()&nbsp; &nbsp; // let us simulate cancellation&nbsp; &nbsp; go func() {&nbsp; &nbsp; &nbsp; &nbsp; <-time.After(time.Millisecond * 200)&nbsp; &nbsp; &nbsp; &nbsp; cancel()&nbsp; &nbsp; }()&nbsp; &nbsp; v := []func(context.Context, chan<- bool){&nbsp; &nbsp; &nbsp; &nbsp; a1,&nbsp; &nbsp; &nbsp; &nbsp; a2,&nbsp; &nbsp; &nbsp; &nbsp; a3,&nbsp; &nbsp; }&nbsp; &nbsp; c := make(chan bool)&nbsp; &nbsp; var wg sync.WaitGroup&nbsp; &nbsp; for _, f := range v {&nbsp; &nbsp; &nbsp; &nbsp; wg.Add(1)&nbsp; &nbsp; &nbsp; &nbsp; f := f&nbsp; &nbsp; &nbsp; &nbsp; go func() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; f(ctx, c)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; wg.Done()&nbsp; &nbsp; &nbsp; &nbsp; }()&nbsp; &nbsp; }&nbsp; &nbsp; go func() {&nbsp; &nbsp; &nbsp; &nbsp; wg.Wait()&nbsp; &nbsp; &nbsp; &nbsp; close(c)&nbsp; &nbsp; }()&nbsp; &nbsp; for v := range c {&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("Received ", v)&nbsp; &nbsp; }}func a1(ctx context.Context, c chan<- bool) {&nbsp; &nbsp; <-time.After(time.Millisecond * 1000)&nbsp; &nbsp; select {&nbsp; &nbsp; case c <- true:&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("Finish 1")&nbsp; &nbsp; case <-ctx.Done():&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("Cancelled 1")&nbsp; &nbsp; }}func a2(ctx context.Context, c chan<- bool) {&nbsp; &nbsp; <-time.After(time.Millisecond * 1000)&nbsp; &nbsp; select {&nbsp; &nbsp; case c <- true:&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("Finish 2")&nbsp; &nbsp; case <-ctx.Done():&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("Cancelled 2")&nbsp; &nbsp; }}func a3(ctx context.Context, c chan<- bool) {&nbsp; &nbsp; <-time.After(time.Millisecond * 1000)&nbsp; &nbsp; select {&nbsp; &nbsp; case c <- true:&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("Finish 3")&nbsp; &nbsp; case <-ctx.Done():&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("Cancelled 3")&nbsp; &nbsp; }}最后回答问题标题Need to run several func() bool and get the first false您可能希望实现流减少。捕获所有值,实现一个小逻辑以尽快关闭您的减排目标。但总是继续完全耗尽它。package mainimport (&nbsp; &nbsp; "context"&nbsp; &nbsp; "fmt"&nbsp; &nbsp; "os"&nbsp; &nbsp; "os/signal"&nbsp; &nbsp; "sync"&nbsp; &nbsp; "time")func main() {&nbsp; &nbsp; ctx, cancel := context.WithCancel(context.Background())&nbsp; &nbsp; go func() {&nbsp; &nbsp; &nbsp; &nbsp; s := make(chan os.Signal, 10)&nbsp; &nbsp; &nbsp; &nbsp; signal.Notify(s)&nbsp; &nbsp; &nbsp; &nbsp; <-s&nbsp; &nbsp; &nbsp; &nbsp; cancel()&nbsp; &nbsp; }()&nbsp; &nbsp; // let us simulate cancellation&nbsp; &nbsp; go func() {&nbsp; &nbsp; &nbsp; &nbsp; <-time.After(time.Millisecond * 200)&nbsp; &nbsp; &nbsp; &nbsp; cancel()&nbsp; &nbsp; }()&nbsp; &nbsp; v := []func(context.Context, chan<- bool){&nbsp; &nbsp; &nbsp; &nbsp; a1,&nbsp; &nbsp; &nbsp; &nbsp; a2,&nbsp; &nbsp; &nbsp; &nbsp; a3,&nbsp; &nbsp; }&nbsp; &nbsp; c := make(chan bool)&nbsp; &nbsp; var wg sync.WaitGroup&nbsp; &nbsp; for _, f := range v {&nbsp; &nbsp; &nbsp; &nbsp; wg.Add(1)&nbsp; &nbsp; &nbsp; &nbsp; f := f&nbsp; &nbsp; &nbsp; &nbsp; go func() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; f(ctx, c)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; wg.Done()&nbsp; &nbsp; &nbsp; &nbsp; }()&nbsp; &nbsp; }&nbsp; &nbsp; // When the above go routines have completed send to q&nbsp; &nbsp; go func() {&nbsp; &nbsp; &nbsp; &nbsp; wg.Wait()&nbsp; &nbsp; &nbsp; &nbsp; close(c)&nbsp; &nbsp; }()&nbsp; &nbsp; firstRes := make(chan bool)&nbsp; &nbsp; go func() {&nbsp; &nbsp; &nbsp; &nbsp; var closed bool&nbsp; &nbsp; &nbsp; &nbsp; for v := range c {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if !v && !closed {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; firstRes <- v&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; closed = true&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; close(firstRes)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("Received ", v)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; if !closed {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; close(firstRes)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }()&nbsp; &nbsp; var wasFalsy bool&nbsp; &nbsp; for v := range firstRes {&nbsp; &nbsp; &nbsp; &nbsp; wasFalsy = !v&nbsp; &nbsp; }&nbsp; &nbsp; fmt.Println("was falsy ", wasFalsy)}func a1(ctx context.Context, c chan<- bool) {&nbsp; &nbsp; <-time.After(time.Millisecond * 2000)&nbsp; &nbsp; select {&nbsp; &nbsp; case c <- !true:&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("Finish 1")&nbsp; &nbsp; case <-ctx.Done():&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("Cancelled 1")&nbsp; &nbsp; }}func a2(ctx context.Context, c chan<- bool) {&nbsp; &nbsp; <-time.After(time.Millisecond * 2000)&nbsp; &nbsp; select {&nbsp; &nbsp; case c <- true:&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("Finish 2")&nbsp; &nbsp; case <-ctx.Done():&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("Cancelled 2")&nbsp; &nbsp; }}func a3(ctx context.Context, c chan<- bool) {&nbsp; &nbsp; <-time.After(time.Millisecond * 2000)&nbsp; &nbsp; select {&nbsp; &nbsp; case c <- true:&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("Finish 3")&nbsp; &nbsp; case <-ctx.Done():&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("Cancelled 3")&nbsp; &nbsp; }}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go