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

下面的代码有一个明显的问题:程序会在工人完成所有工作之前退出。


在发送者开始发送数据之前,worker 的 Goroutines 被启动,数据必须保留。从 sender 函数启动这些 goroutine 不是一种选择。这样做很容易,但是需要学习更复杂的同步技术。


等待工人完成的正确方法是什么?


尝试关闭worker1CH和worker2CH通道,以及为每个工作人员添加专用的 sync.WaitGroups。


package main


import (

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


}

catspeake
浏览 108回答 3
3回答

慕田峪7331174

使用等待组等待两个接收 goroutine 完成。使用一个等待组来等待两个 goroutine。发送完所有值后关闭通道,以便接收 goroutine 中的循环退出。无需等待发送 goroutine。在其他协程完成之前,灌浆会完成所有工作。worker1CH := make(chan int, 1)worker2CH := make(chan int, 1)var wg sync.WaitGroupwg.Add(2)&nbsp; // <-- wait for the two receiving goroutines.// worker for even numbersgo func(wg *sync.WaitGroup, in chan int) {&nbsp; &nbsp; defer wg.Done() // <--- add this line&nbsp; &nbsp; for i := range in {&nbsp; &nbsp; &nbsp; &nbsp; log.Print(i)&nbsp; &nbsp; }}(&wg, worker1CH)// worker for odd numbersgo func(wg *sync.WaitGroup, in chan int) {&nbsp; &nbsp; defer wg.Done() <-- add this line&nbsp; &nbsp; for i := range in {&nbsp; &nbsp; &nbsp; &nbsp; log.Print(i)&nbsp; &nbsp; }}(&wg, worker2CH)// sender which sends even numbers to worker1CH, and odd numbers to worker2CHgo func(evenChan chan int, oddChan chan int) {&nbsp; &nbsp; defer close(evenChan) // <-- close channel so that receiver exits loop&nbsp; &nbsp; defer close(oddChan)&nbsp; // <-- ditto&nbsp; &nbsp; data := rand.Perm(10)&nbsp; &nbsp; for _, i := range data {&nbsp; &nbsp; &nbsp; &nbsp; switch i % 2 {&nbsp; &nbsp; &nbsp; &nbsp; case 0:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; evenChan <- i&nbsp; &nbsp; &nbsp; &nbsp; default:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; oddChan <- i&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}(worker1CH, worker2CH)wg.Wait()

POPMUISE

已经能够创建worker1Done和worker2Done通道,然后等待工作完成。还必须将 close(evenChan) 和 close(oddChan) 添加到 sender 函数以避免fatal error: all goroutines are asleep - deadlock!错误package mainimport (&nbsp; &nbsp; "log"&nbsp; &nbsp; "math/rand"&nbsp; &nbsp; "sync")func main() {&nbsp; &nbsp; worker1CH := make(chan int, 1)&nbsp; &nbsp; worker2CH := make(chan int, 1)&nbsp; &nbsp; worker1Done := make(chan bool)&nbsp; &nbsp; worker2Done := make(chan bool)&nbsp; &nbsp; // worker for even numbers&nbsp; &nbsp; go func(in chan int, done chan bool) {&nbsp; &nbsp; &nbsp; &nbsp; for i := range in {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; log.Print(i)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; done <- true&nbsp; &nbsp; }(worker1CH, worker1Done)&nbsp; &nbsp; // worker for odd numbers&nbsp; &nbsp; go func(in chan int, done chan bool) {&nbsp; &nbsp; &nbsp; &nbsp; for i := range in {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; log.Print(i)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; done <- true&nbsp; &nbsp; }(worker2CH, worker2Done)&nbsp; &nbsp; // sender which sends even numbers to worker1CH, and odd numbers to worker2CH&nbsp; &nbsp; var wg sync.WaitGroup&nbsp; &nbsp; wg.Add(1)&nbsp; &nbsp; go func(wg *sync.WaitGroup, evenChan chan int, oddChan chan int) {&nbsp; &nbsp; &nbsp; &nbsp; defer wg.Done()&nbsp; &nbsp; &nbsp; &nbsp; data := rand.Perm(10)&nbsp; &nbsp; &nbsp; &nbsp; for _, i := range data {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; switch i%2 {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case 0:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; evenChan <- i&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; default:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; oddChan <- i&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; close(evenChan)&nbsp; &nbsp; &nbsp; &nbsp; close(oddChan)&nbsp; &nbsp; }(&wg, worker1CH, worker2CH)&nbsp; &nbsp; wg.Wait()&nbsp; &nbsp; <- worker1Done&nbsp; &nbsp; <- worker2Done}

largeQ

由于您的发件人具有固定大小,因此它将自行退出,您可以关闭阅读器通道并等待package mainimport (&nbsp; &nbsp; "log"&nbsp; &nbsp; "math/rand"&nbsp; &nbsp; "sync")func reader(in chan int, wg *sync.WaitGroup) {&nbsp; &nbsp; defer wg.Done()&nbsp; &nbsp; for i := range in {&nbsp; &nbsp; &nbsp; &nbsp; log.Print(i)&nbsp; &nbsp; }}func main() {&nbsp; &nbsp; var wg sync.WaitGroup&nbsp; &nbsp; worker1CH := make(chan int, 1)&nbsp; &nbsp; worker2CH := make(chan int, 1)&nbsp; &nbsp; wg.Add(1)&nbsp; &nbsp; // worker for even numbers&nbsp; &nbsp; go reader(worker1CH, &wg)&nbsp; &nbsp; wg.Add(1)&nbsp; &nbsp; // worker for odd numbers&nbsp; &nbsp; go reader(worker2CH, &wg)&nbsp; &nbsp; // sender which sends even numbers to worker1CH, and odd numbers to worker2CH&nbsp; &nbsp; sender(worker1CH, worker2CH)&nbsp; &nbsp; close(worker2CH)&nbsp; &nbsp; close(worker1CH)&nbsp; &nbsp; wg.Wait()}func sender(evenChan chan int, oddChan chan int) {&nbsp; &nbsp; data := rand.Perm(10)&nbsp; &nbsp; for _, i := range data {&nbsp; &nbsp; &nbsp; &nbsp; switch i % 2 {&nbsp; &nbsp; &nbsp; &nbsp; case 0:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; evenChan <- i&nbsp; &nbsp; &nbsp; &nbsp; default:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; oddChan <- i&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}游乐场链接https://play.golang.org/p/JJ9ngCHUvbS
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go