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

等待并发工作人员完成后再退出

等待并发工作人员完成后再退出

Go
catspeake 2022-07-11 16:02:30
下面的代码有一个明显的问题:程序会在工人完成所有工作之前退出。在发送者开始发送数据之前,worker 的 Goroutines 被启动,数据必须保留。从 sender 函数启动这些 goroutine 不是一种选择。这样做很容易,但是需要学习更复杂的同步技术。等待工人完成的正确方法是什么?尝试关闭worker1CH和worker2CH通道,以及为每个工作人员添加专用的 sync.WaitGroups。package mainimport (    "log"    "math/rand"    "sync")func main() {    worker1CH := make(chan int, 1)    worker2CH := make(chan int, 1)    // worker for even numbers    go func(in chan int) {        for i := range in {            log.Print(i)        }    }(worker1CH)    // worker for odd numbers    go func(in chan int) {        for i := range in {            log.Print(i)        }    }(worker2CH)    // sender which sends even numbers to worker1CH, and odd numbers to worker2CH    var wg sync.WaitGroup    wg.Add(1)    go func(wg *sync.WaitGroup, evenChan chan int, oddChan chan int) {        defer wg.Done()        data := rand.Perm(10)        for _, i := range data {            switch i%2 {            case 0:                evenChan <- i            default:                oddChan <- i            }        }    }(&wg, worker1CH, worker2CH)    wg.Wait()}
查看完整描述

3 回答

?
慕田峪7331174

TA贡献1828条经验 获得超13个赞

使用等待组等待两个接收 goroutine 完成。使用一个等待组来等待两个 goroutine。


发送完所有值后关闭通道,以便接收 goroutine 中的循环退出。


无需等待发送 goroutine。在其他协程完成之前,灌浆会完成所有工作。


worker1CH := make(chan int, 1)

worker2CH := make(chan int, 1)


var wg sync.WaitGroup

wg.Add(2)  // <-- wait for the two receiving goroutines.


// worker for even numbers

go func(wg *sync.WaitGroup, in chan int) {

    defer wg.Done() // <--- add this line

    for i := range in {

        log.Print(i)

    }

}(&wg, worker1CH)


// worker for odd numbers

go func(wg *sync.WaitGroup, in chan int) {

    defer wg.Done() <-- add this line

    for i := range in {

        log.Print(i)

    }

}(&wg, worker2CH)


// sender which sends even numbers to worker1CH, and odd numbers to worker2CH

go func(evenChan chan int, oddChan chan int) {


    defer close(evenChan) // <-- close channel so that receiver exits loop

    defer close(oddChan)  // <-- ditto


    data := rand.Perm(10)

    for _, i := range data {

        switch i % 2 {

        case 0:

            evenChan <- i

        default:

            oddChan <- i

        }

    }

}(worker1CH, worker2CH)


wg.Wait()


查看完整回答
反对 回复 2022-07-11
?
POPMUISE

TA贡献1765条经验 获得超5个赞

已经能够创建worker1Done和worker2Done通道,然后等待工作完成。


还必须将 close(evenChan) 和 close(oddChan) 添加到 sender 函数以避免fatal error: all goroutines are asleep - deadlock!错误


package main


import (

    "log"

    "math/rand"

    "sync"

)


func main() {


    worker1CH := make(chan int, 1)

    worker2CH := make(chan int, 1)


    worker1Done := make(chan bool)

    worker2Done := make(chan bool)


    // worker for even numbers

    go func(in chan int, done chan bool) {

        for i := range in {

            log.Print(i)

        }

        done <- true

    }(worker1CH, worker1Done)


    // worker for odd numbers

    go func(in chan int, done chan bool) {

        for i := range in {

            log.Print(i)

        }

        done <- true

    }(worker2CH, worker2Done)


    // sender which sends even numbers to worker1CH, and odd numbers to worker2CH

    var wg sync.WaitGroup

    wg.Add(1)

    go func(wg *sync.WaitGroup, evenChan chan int, oddChan chan int) {

        defer wg.Done()


        data := rand.Perm(10)

        for _, i := range data {

            switch i%2 {

            case 0:

                evenChan <- i

            default:

                oddChan <- i

            }

        }


        close(evenChan)

        close(oddChan)


    }(&wg, worker1CH, worker2CH)

    wg.Wait()


    <- worker1Done

    <- worker2Done


}


查看完整回答
反对 回复 2022-07-11
?
largeQ

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

由于您的发件人具有固定大小,因此它将自行退出,您可以关闭阅读器通道并等待


package main


import (

    "log"

    "math/rand"

    "sync"

)


func reader(in chan int, wg *sync.WaitGroup) {

    defer wg.Done()

    for i := range in {

        log.Print(i)

    }

}


func main() {

    var wg sync.WaitGroup


    worker1CH := make(chan int, 1)

    worker2CH := make(chan int, 1)


    wg.Add(1)

    // worker for even numbers

    go reader(worker1CH, &wg)


    wg.Add(1)

    // worker for odd numbers

    go reader(worker2CH, &wg)


    // sender which sends even numbers to worker1CH, and odd numbers to worker2CH

    sender(worker1CH, worker2CH)


    close(worker2CH)

    close(worker1CH)

    wg.Wait()


}


func sender(evenChan chan int, oddChan chan int) {

    data := rand.Perm(10)

    for _, i := range data {

        switch i % 2 {

        case 0:

            evenChan <- i

        default:

            oddChan <- i

        }

    }

}


游乐场链接https://play.golang.org/p/JJ9ngCHUvbS


查看完整回答
反对 回复 2022-07-11
  • 3 回答
  • 0 关注
  • 107 浏览
慕课专栏
更多

添加回答

举报

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