Получите ответы от нескольких подпрограмм go в массив - PullRequest
0 голосов
/ 05 февраля 2019

Мне нужно получить ответы от нескольких подпрограмм go и поместить их в массив.Я знаю, что каналы могут быть использованы для этого, но я не уверен, как я могу убедиться, что все стандартные процедуры завершили обработку результатов.Таким образом я использую группу ожидания.

Код

func main() {
  log.Info("Collecting ints")
  var results []int32
  for _, broker := range e.BrokersByBrokerID {
      wg.Add(1)
      go getInt32(&wg)
  }
  wg.Wait()
  log.info("Collected")
}

func getInt32(wg *sync.WaitGroup) (int32, error) {
  defer wg.Done()

  // Just to show that this method may just return an error and no int32
  err := broker.Open(config)
  if err != nil && err != sarama.ErrAlreadyConnected {
    return 0, fmt.Errorf("Cannot connect to broker '%v': %s", broker.ID(), err)
  }
  defer broker.Close()

  return 1003, nil
}

Мой вопрос

Как я могу поставить все ответыint32 (который может вернуть ошибку) в мой массив int32, убедившись, что все подпрограммы go завершили свою обработку и вернули либо ошибку, либо int?

Ответы [ 2 ]

0 голосов
/ 05 февраля 2019

Я также считаю, что вы должны использовать канал, это должно быть примерно так:

package main

import (
    "fmt"
    "log"
    "sync"
)

var (
    BrokersByBrokerID = []int32{1, 2, 3}
)

type result struct {
    data string
    err string // you must use error type here
}

func main()  {
    var wg sync.WaitGroup
    var results []result
    ch := make(chan result)

    for _, broker := range BrokersByBrokerID {
        wg.Add(1)
        go getInt32(ch, &wg, broker)
    }

    go func() {
        for v := range ch {
            results = append(results, v)
        }
    }()

    wg.Wait()
    close(ch)

    log.Printf("collected %v", results)
}

func getInt32(ch chan result, wg *sync.WaitGroup, broker int32) {
    defer wg.Done()

    if broker == 1 {
        ch <- result{err: fmt.Sprintf("error: gor broker 1")}
        return
    }

    ch <- result{data: fmt.Sprintf("broker %d - ok", broker)}
}

Результат будет выглядеть так:

2019/02/05 15:26:28 collected [{broker 3 - ok } {broker 2 - ok } { error: gor broker 1}]
0 голосов
/ 05 февраля 2019

Если вы не обрабатываете возвращаемые значения функции, запущенной как процедура, они отбрасываются.См. Что происходит с возвращаемым значением из goroutine .

. Вы можете использовать срез для сбора результатов, где каждая goroutine может получить индекс для помещения результатов или, альтернативно, адресэлемент.См. Могу ли я одновременно написать разные элементы среза .Обратите внимание, что если вы используете это, срез должен быть предварительно выделен, и может быть записан только элемент, принадлежащий процедуре, вы не можете «трогать» другие элементы и не можете добавлять к срезу.

Или вы можете использовать канал, по которому goroutines отправляют значения, включающие индекс или ID предмета, который они обработали, чтобы goroutine могла идентифицировать или упорядочить их.См. Как собрать значения из N подпрограмм, выполненных в определенном порядке?

Если обработка должна прекратиться при первой обнаруженной ошибке, см. Закрыть несколько прогонов, если в одной из них произошла ошибкаgo

Вот пример того, как это может выглядеть при использовании канала.Обратите внимание, что здесь не нужна группа ожидания, потому что мы знаем, что ожидаем столько значений на канале, сколько мы запускаем подпрограмм.

type result struct {
    task int32
    data int32
    err  error
}

func main() {
    tasks := []int32{1, 2, 3, 4}

    ch := make(chan result)

    for _, task := range tasks {
        go calcTask(task, ch)
    }

    // Collect results:
    results := make([]result, len(tasks))

    for i := range results {
        results[i] = <-ch
    }

    fmt.Printf("Results: %+v\n", results)
}

func calcTask(task int32, ch chan<- result) {
    if task > 2 {
        // Simulate failure
        ch <- result{task: task, err: fmt.Errorf("task %v failed", task)}
        return
    }

    // Simulate success
    ch <- result{task: task, data: task * 2, err: nil}
}

Вывод (попробуйте на Go Playground ):

Results: [{task:4 data:0 err:0x40e130} {task:1 data:2 err:<nil>} {task:2 data:4 err:<nil>} {task:3 data:0 err:0x40e138}]
...