Голанг делает параллельный запрос и объединяет респон - PullRequest
0 голосов
/ 25 сентября 2018

Я написал код go для независимого вызова нескольких запросов http и объединения результатов.

Иногда в комбинированном методе отсутствуют значения.

func profile(req *http.Request)  (UserMe, error, UserRating, error) {

    wgcall := &sync.WaitGroup{}

    uChan := make(chan ResUser)
    rChan := make(chan ResRating)

        // variable inits
    var meResp UserMe
    var ratingResp UserRating

    go func() {
        res := <-uChan
                meResp = res.Value
    }()

    go func() {
        res := <-rChan
                ratingResp = res.Value
    }()

    wgcall.Add(2)
    go me(req, wgcall, uChan)
    go rate(req, wgcall, rChan)

    wgcall.Wait()

    logrus.Info(meResp)  // sometimes missing
    logrus.Info(ratingResp) // sometimes missing

    return meResp, meErr, ratingResp, ratingErr
}

Но вызовы me и rating возвращают значения из запросов API, как и ожидалось.

func me(req *http.Request, wg *sync.WaitGroup, ch chan ResUser) {
    defer wg.Done()

    // http call return value correclty
    me := ...
    ch <- ResUser{
        Value := // value from rest
    }
    logrus.Info(fmt.Sprintf("User calls  %v" , me))  // always return the values
    close(ch)
}

func rate(req *http.Request, wg *sync.WaitGroup, ch chan ResRating) {
    defer wg.Done()

        // make http call
    rating := ...
    ch <- ResRating{
        Value := // value from rest
    }
    logrus.Info(fmt.Sprintf("Ratings calls %v" , rating)) // always return the values

    close(ch)
}

Проблема: meResp и ratingResp для функции профиля не всегда получают значения.иногда только meResp или ratingResp, иногда оба, как и ожидалось.

Но вызовы функций me и rate всегда получают значения.

Может помочь мне исправить этот plz?

1 Ответ

0 голосов
/ 25 сентября 2018

В вашем коде условие гонки .

Нет никаких препятствий для того, чтобы в методе profile при чтении из uChan и rChan были заполненыпеременные meResp и ratingResp до , которые вы возвращаете из profile.

Вы можете значительно упростить свой код, отказавшись от использования каналов и встроенных объявленных программ в profile.Вместо этого просто заполните значения ответа напрямую.В этих обстоятельствах использование каналов или распрограмм для чтения из них не дает никаких преимуществ, поскольку вы намерены отправить только одно значение, и у вас есть требование, чтобы перед возвратом присутствовали значения, созданные обоими вызовами HTTP.

Выможет сделать это, изменив сигнатуру me и rate, чтобы получить указатель на местоположение для записи их вывода, или обернув их вызовы небольшой функцией, которая получает их выходное значение и заполняет значение в profile.Важно отметить, что WaitGroup должен сигнализироваться только после заполнения значения:

wgcall := &sync.WaitGroup{}

var meResp UserMe
var ratingResp RatingMe

wgcall.Add(2)
// The "me" and "rate" functions should be refactored to
// drop the wait group and channel arguments.
go func() {
    meResp = me(req)
    wgcall.Done()
}()
go func() {
    ratingResp = rate(req)
    wgcall.Done()
}()
wgcall.Wait()

// You are guaranteed that if "me" and "rate" returned valid values,
// they are populated in "meResp" and "ratingResp" at this point.

// Do whatever you need here, such as logging or returning.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...