26

私の要件の 1 つとして、1 つの監視ルーチンによって監視される N 個のワーカー go ルーチンを作成する必要があります。監視ルーチンは、すべてのワーカー ルーチンが完了したときに終了する必要があります。私のコードはデッドロックで終わります。助けてください。

import "fmt"
import "sync"
import "strconv"

func worker(wg *sync.WaitGroup, cs chan string, i int ){
    defer wg.Done()
    cs<-"worker"+strconv.Itoa(i)    
}

func monitorWorker(wg *sync.WaitGroup, cs chan string) {
    defer wg.Done()
    for i:= range cs {
            fmt.Println(i)
     }
}
func main() {
    wg := &sync.WaitGroup{}
    cs := make(chan string)

    for i:=0;i<10;i++{
             wg.Add(1)
             go worker(wg,cs,i)
    } 

    wg.Add(1)
    go monitorWorker(wg,cs)
    wg.Wait()
}
4

2 に答える 2

35

あなたの monitorWorker は死ぬことはありません。すべてのワーカーが終了すると、cs を待ち続けます。このデッドロックは、cs で他に何も送信されないため、wg が 0 に到達しないためです。考えられる修正は、すべてのワーカーが終了したときにモニターがチャネルを閉じることです。for ループが main にある場合は、ループを終了し、main から戻り、プログラムを終了します。

例: http://play.golang.org/p/nai7XtTMfr

package main

import (
    "fmt"
    "strconv"
    "sync"
)

func worker(wg *sync.WaitGroup, cs chan string, i int) {
    defer wg.Done()
    cs <- "worker" + strconv.Itoa(i)
}

func monitorWorker(wg *sync.WaitGroup, cs chan string) {
    wg.Wait()
    close(cs)
}

func main() {
    wg := &sync.WaitGroup{}
    cs := make(chan string)

    for i := 0; i < 10; i++ {
        wg.Add(1)
        go worker(wg, cs, i)
    }

    go monitorWorker(wg, cs)

    for i := range cs {
        fmt.Println(i)

    }
}

編集:これは、OP の最初のコメントに対する回答です。

プログラムには、同期が必要な 3 つの部分があります。まず、すべてのワーカーがデータを送信する必要があります。次に、印刷ループでそのデータを印刷する必要があります。次に、メイン関数が戻る必要があり、それによってプログラムが終了します。あなたの例では、すべてのワーカーがデータを送信し、すべてのデータが出力されますが、正常に返される必要があるというメッセージがメインに送信されることはありません。

私の例では、メインが印刷を行い、「monitorWorker」は、印刷する必要があるすべてのデータを受信したときにメインに通知するだけです。このようにして、プログラムはデッドロックではなく正常に終了します。

印刷ループが別のゴルーチンにあると主張する場合は、それを行うことができます。ただし、追加の通信をメインに送信して返す必要があります。この次の例では、チャネルを使用して、すべてのデータが印刷されたときにメイン エンドを確保します。

package main

import (
    "fmt"
    "strconv"
    "sync"
)

func worker(wg *sync.WaitGroup, cs chan string, i int) {
    defer wg.Done()
    cs <- "worker" + strconv.Itoa(i)
}

func monitorWorker(wg *sync.WaitGroup, cs chan string) {
    wg.Wait()
    close(cs)
}

func printWorker(cs <-chan string, done chan<- bool) {
    for i := range cs {
        fmt.Println(i)
    }

    done <- true
}

func main() {
    wg := &sync.WaitGroup{}
    cs := make(chan string)

    for i := 0; i < 10; i++ {
        wg.Add(1)
        go worker(wg, cs, i)
    }

    go monitorWorker(wg, cs)

    done := make(chan bool, 1)
    go printWorker(cs, done)
    <-done
}
于 2013-11-10T17:52:19.990 に答える