Иди, жди программ, но делай что-то в то же время

#go #concurrency #goroutine

#Вперед #параллелизм #goroutine

Вопрос:

у меня есть следующий исходный код:

 func execTask(input int, results chan<- int) {
    //do stuff (in my case, start process and return something)
    results <- someResult
}

func main() {
    results := make(chan int)

    for _, task := range tasks {
        go execTask(task, results)
    }

    for result := range results {
        fmt.Println(result)
    }
}
  

Для строки for result := range results { я получаю сообщение об ошибке:
fatal error: all goroutines are asleep - deadlock! . В подпрограмме execTask я фактически выполняю процесс с помощью os / exec, поэтому я не знаю, сколько результатов есть results . Поэтому мне нужно дождаться завершения всех моих процессов, но тем временем что-то делать с результатами. Когда все процессы завершаются, моя go-программа тоже может быть завершена.

Как мне это сделать?

Спасибо, Ларс

Комментарии:

1. результаты := make(chan int) для _, задача := диапазон задач { перейти к выполнению задачи (задача, результаты) } Задача также вызывает результаты, что может привести к взаимоблокировке..

Ответ №1:

Вы получаете ошибку взаимоблокировки, потому что вы не закрываете results канал. Следовательно, main продолжает ждать дополнительных данных results даже после того, как все execTask завершены, и больше ничего не записывается results .

Вы можете исправить это, используя sync.WaitGroup :

 func main() {
    var wg sync.WaitGroup
    results := make(chan int)

    wg.Add(len(tasks))
    for _, task := range tasks {
        go func(task int) {
            defer wg.Done()
            execTask(task, results)
        }(task)
    }

    go func() {
        wg.Wait() // wait for each execTask to return
        close(results) // then close the results channel
    }

    for result := range results {
        fmt.Println(result)
    }
}
  

Что касается работы с execTask результатами, пока другие процессы все еще выполняются, у вас уже есть правильная идея. Просто работайте с ними в цикле results диапазона. Запустите там еще несколько программ, если вы хотите больше одновременных выполнений.

Комментарии:

1. Не используйте task из диапазона в вашем закрытии таким образом. Заставьте ваше закрытие принять task int и передать его: см. github.com/golang/go/wiki /…