Цикл Goroutine не завершается - PullRequest
0 голосов
/ 12 октября 2018

Я пытаюсь перебрать массив и скопировать каждое значение в массив.Я хотел бы только раскрутить каждую петлю в отдельной программе.Когда я запускаю его с goroutines, то зацикливаюсь на один размер меньше, чем размер массива (len (Array) -1), но если я избавлюсь от goroutine, то все будет работать нормально.

Я что-то упускаю из-за того, как это должно работать?Кажется очень странным, что это всегда на один меньше, когда запускаешь горутины.Ниже приведен мой код.

func createEventsForEachWorkoutReference(plan *sharedstructs.Plan, user *sharedstructs.User, startTime time.Time, timeZoneKey *string, transactionID *string, monitoringChannel chan interface{}) {
    //Set the activity type as these workouts are coming from plans
    activityType := "workout"
    for _, workoutReference := range plan.WorkoutReferences {
        go func(workoutReference sharedstructs.WorkoutReference) {
            workout, getWorkoutError := workout.GetWorkoutByName(workoutReference.WorkoutID.ID, *transactionID)
            if getWorkoutError == nil && workout != nil {
                //For each workout, create a reference to be inserted into the event
                reference := sharedstructs.Reference{ID: workout.WorkoutID, Type: activityType, Index: 0}
                referenceArray := make([]sharedstructs.Reference, 0)
                referenceArray = append(referenceArray, reference)
                event := sharedstructs.Event{
                    EventID:       uuidhelper.GenerateUUID(),
                    Description:   workout.Description,
                    Type:          activityType,
                    UserID:        user.UserID,
                    IsPublic:      false,
                    References:    referenceArray,
                    EventDateTime: startTime,
                    PlanID:        plan.PlanID}
                //Insert the Event into the databse, I don't handle errors intentionally as it will be async
                creationError := eventdomain.CreateNewEvent(&event, transactionID)
                if creationError != nil {
                    redFalconLogger.LogCritical("plan.createEventsForEachWorkoutReference() Error Creating a workout"+creationError.Error(), *transactionID)
                }
                //add to the outputchannel
                monitoringChannel <- event
                //Calculate the next start time for the next loop
                startTime = calculateNextEventTime(&startTime, &workoutReference.RestTime, timeZoneKey, transactionID)
            }
        }(workoutReference)
    }
    return
}

После немного более глубокого погружения, я думаю, что я выяснил основную причину, но пока не (элегантное) решение.

То, что происходит, заключается в том, чтоМоя вызывающая функция также выполняется в асинхронном режиме и использует "chan interface {}" для отслеживания и потоковой передачи прогресса клиенту.В последнем элементе массива он завершает вызывающую процедуру, прежде чем чан может быть обработан в восходящем направлении.

Как правильно ждать завершения обработки канала.Ниже приведен фрагмент моего модульного теста, который я использую для предоставления контекста.

var wg sync.WaitGroup
wg.Add(1)
go func() {
    defer wg.Done()
    createEventsForEachWorkoutReference(plan, &returnedUser, startDate, &timeZone, &transactionID, monitoringChan)
}()
var userEventArrayList []sharedstructs.Event
go func() {
    for result := range monitoringChan {
        switch result.(type) {
        case sharedstructs.Event:
            counter++
            event := result.(sharedstructs.Event)
            userEventArrayList = append(userEventArrayList, event)
            fmt.Println("Channel Picked Up New Event: " + event.EventID + " with counter " + strconv.Itoa(counter))
        default:
            fmt.Println("No Match")
        }
    }
}()
wg.Wait()
//I COULD SLEEP HERE BUT THAT SEEMS HACKY
close(monitoringChan)

Хотел добавить еще один пример (без моего пользовательского кода).Вы можете закомментировать строку сна, чтобы увидеть, как она работает там со сном.

https://play.golang.org/p/t6L_C4zScP-

1 Ответ

0 голосов
/ 12 октября 2018

Наконец-то понял ответ ...

Проблема заключалась в том, что мне нужно было закрыть свой monitorChan в первой процедуре, а затем отслеживать (Defer wg.close ()) во второй.Отлично сработало, когда я это сделал!

https://play.golang.org/p/fEaZXiWCLt-

...