2013-11-10 3 views
8

Для одного из моих требований мне нужно создать N количество рабочих подпрограмм, которые будут контролироваться одной программой мониторинга. процедура контроля должна заканчиваться, когда все рабочие процедуры завершаются. Мой код заканчивается в тупике, пожалуйста, помогите.все goroutines спали - deadlock

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

ответ

9

Ваш мониторНачало никогда не умирает. Когда все рабочие закончатся, он продолжает ждать на cs. Это взаимоблокировки, потому что больше ничего не будет отправлено на cs, и поэтому wg никогда не достигнет 0. Возможно, решение заключается в том, чтобы монитор закрывал канал, когда все рабочие заканчивают. Если цикл for находится в основном, он завершит цикл, вернется из основного и закончит программу.

Например: 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) 

    } 
} 

Edit: Это ответ на первый комментарий OP в.

Ваша программа имеет три части, которые необходимо синхронизировать. Во-первых, всем вашим работникам необходимо отправить данные. Затем ваш цикл печати должен распечатать эти данные. Затем ваша основная функция должна возвращать, тем самым заканчивая программу. В вашем примере все работники отправляют данные, все данные печатаются, но сообщение никогда не отправляется на главную, чтобы оно возвращалось изящно.

В моем примере, главным образом, печать и «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 
} 
+0

Спасибо за помощь. Но это не решает мою проблему параллельной обработки. В моем случае monitorWorker должен работать параллельно (например, печать с канала). – vrbilgi

+0

@vrbilgi, я прокомментировал ответ. –

+0

Я пробовал разные варианты, но ваш ответ прост и элегантен. Thk: D – vrbilgi