我在Go应用中有一个Web请求处理程序,需要向其他URL发出2+个请求。我想从每个URL收集结果,将每个结果合并到一个JSON对象中,并通过我的请求处理程序返回。请求不依赖于彼此,也不需要排序。
在Go中执行此操作的最佳模式是什么?我应该使用频道和WaitGroup
吗?
答案 0 :(得分:1)
对于简单的事情,我会使用一组局部变量和一些设置这些变量的goroutine,以及一个等待组来知道什么时候完成:
var a string
var b string
wg := sync.WaitGroup{}
wg.Add(2)
go func(){
time.Sleep(5 * time.Second) // make a request
a = "foo"
wg.Done()
}()
go func(){
time.Sleep(3 * time.Second) // make a request
b = "bar"
wg.Done()
}()
wg.Wait()
fmt.Println(a,b) //combine results
如果您想要更复杂的行为,例如超时或部分结果,那么您可能希望子请求在您可以选择的频道上传回结果:
// make sure to buffer to max number of senders so garbage collection can clean up
// if we time out
ch := make(chan string, 2)
go func() {
time.Sleep(5 * time.Second) // make a request
ch <- "foo"
}()
go func() {
time.Sleep(2 * time.Second) // make a request
ch <- "bar"
}()
results := []string{}
timeout := time.After(4 * time.Second)
Loop:
for {
select {
case r := <-ch:
results = append(results, r)
if len(results) == 2 {
break Loop
}
case <-timeout:
break Loop
}
}
fmt.Println(results)
这并不能完全保留秩序,但如果这很重要,你可以制作另一个频道。无论如何,这是一般的想法。
答案 1 :(得分:0)
我编写了这个库,可以帮助简化并行运行go例程,而不必担心低级细节https://github.com/shomali11/parallelizer
所以在你的情况下,你可以这样做:
package main
import (
"github.com/shomali11/parallelizer"
"fmt"
)
func main() {
group := parallelizer.DefaultGroup()
result1 := &SomeResultStructure{}
group.Add(func(result *SomeResultStructure) {
return func () {
...
result.SomeValue = "1"
}
}(result1))
result2 := &SomeResultStructure{}
group.Add(func(result *SomeResultStructure) {
return func () {
...
result.SomeValue = "2"
}
}(result2))
err := group.Run()
fmt.Println("Done")
fmt.Println(fmt.Sprintf("Results 1: %v", result1.SomeValue))
fmt.Println(fmt.Sprintf("Results 2: %v", result2.SomeValue))
fmt.Printf("Error: %v", err)
}
输出:
Done
Results 1: 1
Results 2: 2
Error: <nil>