sync.WaitGroup控制无效?

yaxiaomu · 2020-05-09 10:26:37 · 1202 次点击 · 大约8小时之前 开始浏览    置顶
这是一个创建于 2020-05-09 10:26:37 的主题,其中的信息可能已经有所发展或是发生改变。

实际输出: main done

期望输出:有bug !main done

package main

import (
    "fmt"
    "sync"
)

func main() {

    ch2 := make(chan int, 1000)
    var wg sync.WaitGroup
    go testThreadSate01(ch2, &wg)
    go testThreadSate02(ch2, &wg)
    go testThreadSate03(ch2, &wg)
    go func() {
        for {
            select {
            case res := <-ch2:
                if res == 28 {
                    break
                }
            case resGt := <-ch2:
                if resGt > 28 {
                    fmt.Println("有bug !")
                    break
                }
            default:
            }
        }
    }()

    wg.Wait()
    fmt.Println("main done")

}
func testThreadSate03(ch chan int, wg *sync.WaitGroup) {
    defer wg.Done()
    wg.Add(1)
    for j := 21; j <= 30; j++ {
        ch <- j
    }
}
func testThreadSate01(ch chan int, wg *sync.WaitGroup) {
    defer wg.Done()
    wg.Add(1)
    for j := 0; j <= 10; j++ {
        ch <- j
    }
}
func testThreadSate02(ch chan int, wg *sync.WaitGroup) {
    defer wg.Done()
    wg.Add(1)
    //time.Sleep(1 * time.Microsecond)
    for j := 11; j <= 20; j++ {
        ch <- j
    }
}

有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1202 次点击  
加入收藏 微博
6 回复  |  直到 2020-05-09 13:20:20
xoxzzz
xoxzzz · #1 · 5年之前

实际上你的协程可能来不及执行wg.Add(1)主程就退出了,而且你的go func() {}是个死循环只不过你的主程没有去等待这个协程才没有卡住

yaxiaomu
yaxiaomu · #2 · 5年之前
xoxzzzxoxzzz #1 回复

实际上你的协程可能来不及执行wg.Add(1)主程就退出了,而且你的go func() {}是个死循环只不过你的主程没有去等待这个协程才没有卡住

嗯,理解,有什么补救办法吗,我改了另外一种方式,

package main

import (
    "fmt"
    "sync"
)

func main() {

    ch2 := make(chan int, 1000)
    var wg sync.WaitGroup
    wg.Add(4)
    go testThreadSate01(ch2, &wg)
    go testThreadSate02(ch2, &wg)
    go testThreadSate03(ch2, &wg)
    go func(wg *sync.WaitGroup) {
        for {
            select {
            case res := <-ch2:
                if res == 28 {
                    break
                }
            case resGt := <-ch2:
                if resGt > 28 {
                    fmt.Println("有bug !")
                    wg.Done()
                }
            default:
            }
        }
    }(&wg)

    wg.Wait()
    fmt.Println("main done")

}
func testThreadSate03(ch chan int, wg *sync.WaitGroup) {
    defer wg.Done()
    for j := 21; j <= 30; j++ {
        ch <- j
    }
}
func testThreadSate01(ch chan int, wg *sync.WaitGroup) {
    defer wg.Done()
    for j := 0; j <= 10; j++ {
        ch <- j
    }
}
func testThreadSate02(ch chan int, wg *sync.WaitGroup) {
    defer wg.Done()
    //time.Sleep(1 * time.Microsecond)
    for j := 11; j <= 20; j++ {
        ch <- j
    }
}
yaxiaomu
yaxiaomu · #3 · 5年之前

这样吧。。

func main() {

    ch2 := make(chan int, 1000)
    var wg sync.WaitGroup
    wg.Add(3)
    go testThreadSate01(ch2, &wg)
    go testThreadSate02(ch2, &wg)
    go testThreadSate03(ch2, &wg)
    wg.Wait()
    for {
        select {
        case resGt := <-ch2:
            if resGt > 28 {
                fmt.Println("有bug !")
                goto OUT
            }
        default:
        }
    }
OUT:
    fmt.Println("----")
    fmt.Println("main done")

}
qysz
qysz · #4 · 5年之前

break跳出的是select,不是for循环;select会随机执行满足条件的语句,感觉case resGt := <-ch2:有概率一次都不执行,然后程序卡住。

yaxiaomu
yaxiaomu · #5 · 5年之前

完整版

package main

import (
    "fmt"
    "sync"
    "time"
)

func main() {
    ch2 := make(chan int, 1000)
    var wg sync.WaitGroup
    wg.Add(4)
    go testThreadSate01(ch2, &wg)
    go testThreadSate02(ch2, &wg)
    go testThreadSate03(ch2, &wg)

    go func(wg *sync.WaitGroup) {
        for {
            select {
            case resGt := <-ch2:
                if resGt > 28 {
                    fmt.Println("bug:lwq")
                    goto OUT
                }
                fmt.Println(resGt)
            }
        }
    OUT:
        wg.Done()
        fmt.Println("----")

    }(&wg)
    wg.Wait()
    fmt.Println("all groutine done")
    fmt.Println("main done")


}

func testThreadSate03(ch chan int, wg *sync.WaitGroup) {
    defer wg.Done()
    time.Sleep(1 * time.Second)
    for j := 21; j <= 30; j++ {
        ch <- j
    }
}
func testThreadSate01(ch chan int, wg *sync.WaitGroup) {
    defer wg.Done()
    for j := 0; j <= 10; j++ {
        ch <- j
    }
}
func testThreadSate02(ch chan int, wg *sync.WaitGroup) {
    defer wg.Done()

    for j := 11; j <= 20; j++ {
        ch <- j
    }
}
yaxiaomu
yaxiaomu · #6 · 5年之前

完整优化wgDone传值版

package main

import (
    "fmt"
    "sync"
    "time"
)

func main() {
    ch2 := make(chan int, 1000)
    var wg sync.WaitGroup
    wg.Add(4)

    go testThreadSate01(ch2, wg.Done)
    go testThreadSate02(ch2, wg.Done)
    go testThreadSate03(ch2, wg.Done)
    go func(wg *sync.WaitGroup) {
        for {
            select {
            case resGt := <-ch2:
                if resGt > 28 {
                    fmt.Println("bug:lwq")
                    goto OUT
                }
                fmt.Println(resGt)
            }
        }
    OUT:
        wg.Done()
        fmt.Println("----")

    }(&wg)
    wg.Wait()
    fmt.Println("all groutine done")
    fmt.Println("main done")

}

func testThreadSate03(ch chan int, wgDone func()) {
    wgDone()
    time.Sleep(1 * time.Second)
    for j := 21; j <= 30; j++ {
        ch <- j
    }
}
func testThreadSate01(ch chan int, wgDone func()) {
    wgDone()
    for j := 0; j <= 10; j++ {
        ch <- j
    }
}
func testThreadSate02(ch chan int, wgDone func()) {
    wgDone()
    for j := 11; j <= 20; j++ {
        ch <- j
    }
}
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传