我需要从多个go例程获取响应并将它们放入数组中。我知道可以使用通道,但是我不确定如何确保所有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?
答案 0 :(得分:1)
如果不处理作为goroutine启动的函数的返回值,则将其丢弃。参见What happens to return value from goroutine。
您可以使用切片来收集结果,其中每个goroutine都可以接收将结果放入的索引,或者元素的地址。参见Can I concurrently write different slice elements。请注意,如果使用此选项,则必须预先分配切片,并且只能写入属于goroutine的元素,不能“触摸”其他元素,也不能追加到切片。
或者您可以使用一个通道,goroutine会在该通道上发送包含所处理项目的索引或ID的值,以便收集goroutine可以识别或排序它们。参见How to collect values from N goroutines executed in a specific order?
如果应该在遇到第一个错误时停止处理,请参见Close multiple goroutine if an error occurs in one in go
这是一个使用频道时的示例。请注意,这里不需要等待组,因为我们知道我们期望通道上的值与启动的goroutine一样多。
@api_view(['POST'])
def SaveVisitView(request):
if request.method == 'POST':
visits = json.loads(request.POST.get('request'))
visits['visits'][0].update({'user': visits['user']})
visit = [] #need to return last inserted visit_id
visit_data = [] #need to return last inserted vdata_id
visit_child = [] #need to return last inserted vchild_id
for i in range(len(visits['visits'])):
for z in range(len(visits['visits'][i]['data'])-1):
visits['visits'][i]['data'][z]['parameter_id'] = visits['visits'][i]['data'][z]['VisitParamID']
if visits['visits'][i]['data'][z]['parameter_id'] == '5' or visits['visits'][i]['data'][z]['parameter_id'] == '28':
visits['visits'][i].update({'data_child': [visits['visits'][i]['data'][z]]})
del visits['visits'][i]['data'][z]
serializer = VisVisitsSerializer(data=visits['visits'][i])
if serializer.is_valid():
if visits['visits'][i]['action'] == "i":
serializer.save()
#print(serializer[i]['visit_id'])
# visit_save.save()
visit_data.append({'visit_ids':serializer[i]['visit_id']})
del visits['visits'][i]['data_child']
elif visits['visits'][i]['action'] == "u" :
VisVisits.objects.filter(visit_id=visits['visits'][i]['visit_id']).update(is_valid=visits['visits'][i]['active'])
visit_data_update.append({'visit_id':serializer.data.visit_id })
del visits['visits'][i]['data_child']
else:
visit_issues.append({'local_id':visits['visits'][i]['local_id'],
'validation_issues': serializer.errors,
'status':status.HTTP_400_BAD_REQUEST})
return Response({'visit_issues':visit_issues,
'visit_data': visit_data,
'status': status.HTTP_201_CREATED} )
输出(在Go Playground上尝试输入):
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}
}
答案 1 :(得分:1)
我也相信您必须使用频道,它必须是这样的:
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}]