Голанг Чан зависает, просматривая результаты - PullRequest
0 голосов
/ 10 октября 2018

Я довольно новичок в каналах GoLang, но он не работает так, как я ожидал.

У меня есть функция, для которой я хочу вызвать 3 отдельные программы и затем дождаться их завершения.Если я получаю сообщение об ошибке, я пытаюсь поместить его в CHAN, а затем обработать ошибку после завершения wg.Wait().

К сожалению, при циклическом просмотре результатов CHAN он зависает.Я предполагаю, что он все еще ждет, пока ЧАН заполнится, но не все программы будут выдавать ошибки.

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

Ниже мой код.

func createWorkoutPlanForUserPreconditionCheck(planID, userID, transactionID *string) (*sharedstructs.Plan, *sharedstructs.User, *sharedstructs.Profile, error) {
    if planID == nil || userID == nil || transactionID == nil {
        return nil, nil, nil, sharedstructs.InvalidData{Msg: "Cannot pass in Nil Parameters"}
    }

    plan := sharedstructs.Plan{}
    user := sharedstructs.User{}
    profile := sharedstructs.Profile{}
    //myError := sharedstructs.InvalidData{}
    ch := make(chan sharedstructs.InvalidData, 3)

    var wg sync.WaitGroup
    wg.Add(3)
    //Get the Plan from the Plan ID
    go func() {
        defer wg.Done()
        returnedPlan, readError := readPlan(*planID)
        if readError != nil || returnedPlan == nil {
            ch <- sharedstructs.InvalidData{Msg: "Could Not Retreive the User with ID: " + *userID}
        } else {
            plan = *returnedPlan
        }
    }()

    //Get the User
    go func() {
        defer wg.Done()
        returnedUser, getUserError := userdomain.GetUserByID(*userID, *transactionID)
        if getUserError != nil || &returnedUser == nil {
            ch <- sharedstructs.InvalidData{Msg: "Could Not Retreive the User with ID: " + *userID}
        } else {
            user = returnedUser
        }
    }()

    //Get the Profile
    go func() {
        defer wg.Done()
        readProfile, getProfileError := profiledomain.GetProfile(*userID, *transactionID)
        if getProfileError != nil || readProfile == nil {
            ch <- sharedstructs.InvalidData{Msg: "Could Not Retreive the User with ID: " + *userID}
        } else {
            profile = *readProfile
        }
    }()

    wg.Wait()

    ////"Hangs Here" - PUT MY ERROR HANDLING LOGIC HERE
    for err := range ch {
        fmt.Println(err.Error())
    }

    return &plan, &user, &profile, nil
}

1 Ответ

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

Итак, вскоре после публикации я нашел решение.Моя проблема была на самом деле двоякой:

  1. Закрытие моего канала, чтобы он знал, когда прекратить прослушивание
  2. Использование несовместимых методов для передачи моих данных из моей программы в мою вызывающую функцию.Для ошибок я использовал chans, но для пользовательских структур я просто устанавливал его.Я преобразовал свой канал в интерфейс {}, а затем переключил его при обработке, чтобы определить тип структуры.

^^^ Исправление этих проблем заставило мой код работать, но здесьэто то, что мой код закончился как ..

func createWorkoutPlanForUserPreconditionCheck(planID, userID, transactionID *string) (*sharedstructs.Plan, *sharedstructs.User, *sharedstructs.Profile, error) {
    if planID == nil || userID == nil || transactionID == nil {
        return nil, nil, nil, sharedstructs.InvalidData{Msg: "Cannot pass in Nil Parameters"}
    }

    outputChannel := make(chan interface{}, 3)
    var wg sync.WaitGroup
    wg.Add(3)

    //Get the Plan from the Plan ID
    go func() {
        defer wg.Done()
        returnedPlan, readError := readPlan(*planID)
        if readError != nil || returnedPlan == nil {
            outputChannel <- sharedstructs.InvalidData{Msg: "Could Not Retreive the User with ID: " + *userID}
        } else {
            outputChannel <- *returnedPlan
        }
    }()

    //Get the User
    go func() {
        defer wg.Done()
        returnedUser, getUserError := userdomain.GetUserByID(*userID, *transactionID)
        if getUserError != nil || &returnedUser == nil {
            outputChannel <- sharedstructs.InvalidData{Msg: "Could Not Retreive the User with ID: " + *userID}
        } else {
            outputChannel <- returnedUser
        }
    }()

    //Get the Profile
    go func() {
        defer wg.Done()
        readProfile, getProfileError := profiledomain.GetProfile(*userID, *transactionID)
        if getProfileError != nil || readProfile == nil {
            outputChannel <- sharedstructs.InvalidData{Msg: "Could Not Retreive the User with ID: " + *userID}
        } else {
            outputChannel <- *readProfile
        }
    }()

    wg.Wait()
    close(outputChannel)

    plan := sharedstructs.Plan{}
    user := sharedstructs.User{}
    profile := sharedstructs.Profile{}
    for result := range outputChannel {
        switch result.(type) {
        case sharedstructs.InvalidData:
            return nil, nil, nil, result.(sharedstructs.InvalidData)
        case sharedstructs.Plan:
            plan = result.(sharedstructs.Plan)
        case sharedstructs.User:
            user = result.(sharedstructs.User)
        case sharedstructs.Profile:
            profile = result.(sharedstructs.Profile)
        }
    }

    return &plan, &user, &profile, nil
}
...