【问题标题】:Goroutine loop not completingGoroutine 循环未完成
【发布时间】:2018-10-12 05:15:33
【问题描述】:

我正在尝试遍历数组并复制数组中的每个值。我想在一个单独的 goroutine 中分离每个循环。当我使用 goroutines 运行它时,将循环比数组的大小小一个 (len(Array) -1) 但如果我摆脱 goroutines 则它处理得很好。

我是否遗漏了一些关于它应该如何工作的东西?运行 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
}

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

似乎正在发生的事情是我的调用函数也在异步 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-

【问题讨论】:

  • 尽量给出最小的例子,满足你想要的,不要只是从你的项目中复制和粘贴你的代码。
  • 感谢您的帮助,我尝试在循环中使用 Wg.Wait(),但似乎没有帮助。当我将它放在 goroutine 中时,它不会处理循环中的每个项目,但是当我同步执行时,它会处理。很明显,我遗漏了一些关于 goroutines 是如何工作的东西。会继续尝试其他事情。
  • 我已经找到了根本原因,但还不知道解决方案。我的调用函数在 goroutine 中运行它的处理并在 chan(类型为 interface{})上“监听”。它正在完成最后一个循环并在 chan 实际更新之前返回。因此,在调用 goroutine 完成之前,最后一项的 chan 处理没有完成。有没有办法(除了 time.Sleep())来确保完成 chan 处理?我会将代码发布到 OP。

标签: go goroutine


【解决方案1】:

终于找到答案了……

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-03-18
    • 2020-11-27
    • 2020-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-29
    • 2019-06-18
    相关资源
    最近更新 更多