从 goroutines 中获取结果的最佳方法
Best approach to getting results out of goroutines
我有两个功能无法更改(请参阅下面的 first()
和 second()
)。他们正在返回一些数据和错误(输出数据不同,但在下面的示例中,为简单起见,我使用 (string, error)
)
我想 运行 它们在单独的 goroutine 中 - 我的方法:
package main
import (
"fmt"
"os"
)
func first(name string) (string, error) {
if name == "" {
return "", fmt.Errorf("empty name is not allowed")
}
fmt.Println("processing first")
return fmt.Sprintf("First hello %s", name), nil
}
func second(name string) (string, error) {
if name == "" {
return "", fmt.Errorf("empty name is not allowed")
}
fmt.Println("processing second")
return fmt.Sprintf("Second hello %s", name), nil
}
func main() {
firstCh := make(chan string)
secondCh := make(chan string)
go func() {
defer close(firstCh)
res, err := first("one")
if err != nil {
fmt.Printf("Failed to run first: %v\n", err)
}
firstCh <- res
}()
go func() {
defer close(secondCh)
res, err := second("two")
if err != nil {
fmt.Printf("Failed to run second: %v\n", err)
}
secondCh <- res
}()
resultsOne := <-firstCh
resultsTwo := <-secondCh
// It's important for my app to do error checking and stop if errors exist.
if resultsOne == "" || resultsTwo == "" {
fmt.Println("There was an ERROR")
os.Exit(1)
}
fmt.Println("ONE:", resultsOne)
fmt.Println("TWO:", resultsTwo)
}
我相信一个警告是 resultsOne := <- firstCh
阻塞直到第一个 goroutine 完成,但我不太关心这个。
能否请您确认我的方法是好的?还有哪些其他方法更适合我的情况?
这个例子看起来很不错。一些改进是:
- 声明您的频道已缓冲
firstCh := make(chan string, 1)
secondCh := make(chan string, 1)
对于无缓冲通道,发送操作阻塞(直到有人接收)。如果你的 goroutine #2 比第一个快得多,它也必须等到第一个完成,因为你按顺序收到:
resultsOne := <-firstCh // waiting on this one first
resultsTwo := <-secondCh // sender blocked because the main thread hasn't reached this point
- 使用
"golang.org/x/sync/errgroup".Group
。该程序会让人感觉“不太原生”,但它使您无需手动管理频道——在非人为设置中进行交易,以同步写入结果:
func main() {
var (
resultsOne string
resultsTwo string
)
g := errgroup.Group{}
g.Go(func() error {
res, err := first("one")
if err != nil {
return err
}
resultsOne = res
return nil
})
g.Go(func() error {
res, err := second("two")
if err != nil {
return err
}
resultsTwo = res
return nil
})
err := g.Wait()
// ... handle err
我有两个功能无法更改(请参阅下面的 first()
和 second()
)。他们正在返回一些数据和错误(输出数据不同,但在下面的示例中,为简单起见,我使用 (string, error)
)
我想 运行 它们在单独的 goroutine 中 - 我的方法:
package main
import (
"fmt"
"os"
)
func first(name string) (string, error) {
if name == "" {
return "", fmt.Errorf("empty name is not allowed")
}
fmt.Println("processing first")
return fmt.Sprintf("First hello %s", name), nil
}
func second(name string) (string, error) {
if name == "" {
return "", fmt.Errorf("empty name is not allowed")
}
fmt.Println("processing second")
return fmt.Sprintf("Second hello %s", name), nil
}
func main() {
firstCh := make(chan string)
secondCh := make(chan string)
go func() {
defer close(firstCh)
res, err := first("one")
if err != nil {
fmt.Printf("Failed to run first: %v\n", err)
}
firstCh <- res
}()
go func() {
defer close(secondCh)
res, err := second("two")
if err != nil {
fmt.Printf("Failed to run second: %v\n", err)
}
secondCh <- res
}()
resultsOne := <-firstCh
resultsTwo := <-secondCh
// It's important for my app to do error checking and stop if errors exist.
if resultsOne == "" || resultsTwo == "" {
fmt.Println("There was an ERROR")
os.Exit(1)
}
fmt.Println("ONE:", resultsOne)
fmt.Println("TWO:", resultsTwo)
}
我相信一个警告是 resultsOne := <- firstCh
阻塞直到第一个 goroutine 完成,但我不太关心这个。
能否请您确认我的方法是好的?还有哪些其他方法更适合我的情况?
这个例子看起来很不错。一些改进是:
- 声明您的频道已缓冲
firstCh := make(chan string, 1)
secondCh := make(chan string, 1)
对于无缓冲通道,发送操作阻塞(直到有人接收)。如果你的 goroutine #2 比第一个快得多,它也必须等到第一个完成,因为你按顺序收到:
resultsOne := <-firstCh // waiting on this one first
resultsTwo := <-secondCh // sender blocked because the main thread hasn't reached this point
- 使用
"golang.org/x/sync/errgroup".Group
。该程序会让人感觉“不太原生”,但它使您无需手动管理频道——在非人为设置中进行交易,以同步写入结果:
func main() {
var (
resultsOne string
resultsTwo string
)
g := errgroup.Group{}
g.Go(func() error {
res, err := first("one")
if err != nil {
return err
}
resultsOne = res
return nil
})
g.Go(func() error {
res, err := second("two")
if err != nil {
return err
}
resultsTwo = res
return nil
})
err := g.Wait()
// ... handle err