#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 /…