drfu80954 2018-10-12 05:15
浏览 70
已采纳

Goroutine循环未完成

I am attempting to loop through an Array and copy each value within an array. I would like to but spin each loop off in a separate goroutine. When I do run it with goroutines then will loop one less than the size of the array (len(Array) -1) but if I get rid of the goroutine then it processes just fine.

Am I missing something about how this should work? It seems very odd that it is always one less when running goroutines. Below is my code.

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
}

After a bit deeper dive, I think that I figured the root cause but not the (elegant) solution yet.

What appears to be happening is that my calling function is running in an async goroutine as well and using a "chan interface{}" to monitor and stream progress back to the client. On the last item in the array, it is completing the calling goroutine before the chan can be processed upstream.

What is the proper way to wait for the channel processing to complete. Below is a portion of my unit test that I am using to provide context.

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)

Wanted to add one more example (without my custom code). You can comment out the sleep line to see it work with sleep in there.

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

  • 写回答

1条回答 默认 最新

  • douyakan8924 2018-10-12 16:17
    关注

    Finally figured the answer...

    The problem was that I needed to close my monitoringChan in the first goroutine and then monitor (Defer wg.close()) in the second goroutine. Worked great when I did that!

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

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 stm32开发clion时遇到的编译问题
  • ¥15 lna设计 源简并电感型共源放大器
  • ¥15 如何用Labview在myRIO上做LCD显示?(语言-开发语言)
  • ¥15 Vue3地图和异步函数使用
  • ¥15 C++ yoloV5改写遇到的问题
  • ¥20 win11修改中文用户名路径
  • ¥15 win2012磁盘空间不足,c盘正常,d盘无法写入
  • ¥15 用土力学知识进行土坡稳定性分析与挡土墙设计
  • ¥70 PlayWright在Java上连接CDP关联本地Chrome启动失败,貌似是Windows端口转发问题
  • ¥15 帮我写一个c++工程