2014-01-29 2 views
1

Я строю скелет рабочей системы, используя Go, и я получаю «фатальную ошибку: все горуты спали - тупик!».все спящие процедуры спят - deadlock

Я использую два канала для координации, один для создания заданий, а второй для отправки результатов. После создания заданий я закрываю входной канал.

Мой вопрос заключается в том, как закрыть выходной канал, чтобы программа могла выйти правильно. Код:

package main 

import (
    "bufio" 
    "flag" 
    "fmt" 
    "log" 
    "math/rand" 
    "os" 
    "time" 
) 

type Work struct { 
    id int 
    ts time.Duration 
} 

const (
    NumWorkers = 5000 
    NumJobs = 100000 
) 

func worker(in <-chan *Work, out chan<- *Work) { 
    for w := range in { 
     st := time.Now() 
     time.Sleep(time.Duration(rand.Int63n(int64(200 * time.Millisecond)))) 
     w.ts = time.Since(st) 
     out <- w 
    } 
} 

func main() { 
    wait := flag.Bool("w", false, "wait for <enter> before starting") 
    flag.Parse() 

    if *wait { 
     fmt.Printf("I'm <%d>, press <enter> to continue", os.Getpid()) 
     reader := bufio.NewReader(os.Stdin) 
     reader.ReadString('\n') 
    } 

    Run() 
} 

func Run() { 
    in, out := make(chan *Work, 100), make(chan *Work, 100) 
    for i := 0; i < NumWorkers; i++ { 
     go worker(in, out) 
    } 
    go createJobs(in) 
    receiveResults(out) 
} 

func createJobs(queue chan<- *Work) { 
    for i := 0; i < NumJobs; i++ { 
     work := &Work{i, 0} 
     queue <- work 
    } 
    close(queue) 
} 

func receiveResults(completed <-chan *Work) { 
    for w := range completed { 
     log.Printf("job %d completed in %s", w.id, w.ts) 
    } 
} 

Любая помощь приветствуется :)

+0

Существует много информации, напечатанной (штат gorutines), которые помогают диагностировать такие проблемы – Arjan

ответ

1

я пропустил часть о вас, зная причину тупика, в оригинальный ответ.

  • Вы упомянули WaitGroup, то есть в основном только семафор
  • Вы можете использовать другой канал "контроль", что работники Sinal когда они сделаны

-

func worker(ctrl chan<- bool, in <-chan *Work, out chan<- *Work) { 
    for w := range in { 
     st := time.Now() 
     time.Sleep(time.Duration(rand.Int63n(int64(200 * time.Millisecond)))) 
     w.ts = time.Since(st) 
     out <- w 
    } 
    ctrl <- true 
} 

func control(ctrl <-chan bool, numWorkers int, out chan<- *Work) { 
    for i=0; i<numWorkers; i++ { 
     <-ctrl 
    } 
    close(out) 
} 

оригинал ответ:

Вы делаете range по завершении:

for w := range completed { 
    log.Printf("job %d completed in %s", w.id, w.ts) 
} 

, но этот канал никогда не закрывается

+0

Correct. Я думал использовать WaitGroup, чтобы закрыть завершенный канал, поскольку я не против этого. –

+0

Я пропустил последнее предложение в вашем описании. Ну, это одно из возможных решений. – Arjan

+0

Arjan, я использую канал управления, как вы предлагали, большое спасибо :) –