Если вы хотите, чтобы 2 рабочие программы завершились до начала следующей итерации, просто переместите вызов wg.Wait()
в конец тела цикла:
for key, value := range schoolList {
value2 := value
fmt.Println(key, ":", value)
wg.Add(1)
go func() {
defer wg.Done()
std <- fetchStudentsFromSchool(wg, value2.CleverSchoolID, token)
}()
wg.Add(1)
go func() {
defer wg.Done()
tch <- fetchTeachersFromSchool(wg, value2.CleverSchoolID, token)
}()
students = <-std
teachers = <-tch
wg.Wait()
}
Также обратите внимание, что если вы уже используете каналы для доставки результатов процедуры, и если никто больше не использует каналы std
и tch
, WaitGroup
даже не требуется:
for key, value := range schoolList {
value2 := value
fmt.Println(key, ":", value)
go func() {
std <- fetchStudentsFromSchool(wg, value2.CleverSchoolID, token)
}()
go func() {
tch <- fetchTeachersFromSchool(wg, value2.CleverSchoolID, token)
}()
students = <-std
teachers = <-tch
}
Этого достаточно, потому что следующая итерация может начаться, только если завершены оба приема от std
и tch
, но это может произойти, только если рабочие программы выполняют свою работу и отправляют результат по этим каналам.
Теперь, если мы подумаем над тем, что это делает: процедура цикла ожидает двух рабочих процедур, чтобы завершить свою работу и затем перейти (к следующей итерации). Пока 2 рабочих работают, он просто ждет.
Мы можем упростить и улучшить это, выполнив работу 1 рабочего в цикле цикла, а когда закончите, подождите, пока один рабочий также завершит работу (если еще не закончил).
Вот как это может выглядеть:
for key, value := range schoolList {
value2 := value
fmt.Println(key, ":", value)
go func() {
std <- fetchStudentsFromSchool(wg, value2.CleverSchoolID, token)
}()
teachers = fetchTeachersFromSchool(wg, value2.CleverSchoolID, token)
students = <-std
}
Мы просто выбираем учителей в цикле цикла, и только выбираем студентов в параллельной программе. Это имеет тот же эффект (студенты и преподаватели выбираются одновременно), с меньшими накладными расходами и более чистым кодом.
Также обратите внимание, что, поскольку теперь у вас есть синхронизация, чтобы не запускать следующую итерацию до тех пор, пока рабочие не закончат, вам не нужно делать копию переменной цикла: она не будет изменяться в течение жизни рабочих. Таким образом, вы можете просто использовать:
for key, value := range schoolList {
fmt.Println(key, ":", value)
go func() {
std <- fetchStudentsFromSchool(wg, value.CleverSchoolID, token)
}()
teachers = fetchTeachersFromSchool(wg, value.CleverSchoolID, token)
students = <-std
}
(Это относится и к решению с waitgroup.)