代码之家  ›  专栏  ›  技术社区  ›  mornindew

Goroutine循环未完成

  •  -5
  • mornindew  · 技术社区  · 6 年前

    我是不是错过了该怎么做?运行goroutines时总是少一个,这似乎很奇怪。下面是我的代码。

    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
    }
    

    在深入研究之后,我认为我找到了根本原因,但还没有找到(优雅的)解决方案。

    似乎正在发生的是,我的调用函数也在异步goroutine中运行,并使用“chan interface{}”监视进度并将其流式传输回客户端。在数组中的最后一项上,它正在完成调用goroutine,然后才能在上游处理chan。

    等待通道处理完成的正确方法是什么。下面是我用来提供上下文的单元测试的一部分。

    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)
    

    想再添加一个示例(没有我的自定义代码)。你可以注释掉sleep行,看看它在sleep中的作用。

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

    1 回复  |  直到 6 年前
        1
  •  0
  •   mornindew    6 年前

    终于找到了答案。。。

    问题是我需要在第一个goroutine中关闭monitoringChan,然后在第二个goroutine中关闭monitor(Defer wg.close())。当我这么做的时候效果很好!

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