源码索引 / CURRENT IMPLEMENTATION
learning/go-patterns/stages/05-parallel/main.go
60 行 · 点击行号可定位;函数链接随声明位置更新,不手填行号。
跳到函数 / 声明
// Stage 05: start two independent tasks concurrently and collect both results.
package main
import (
"context"
"errors"
"fmt"
)
// Task is one unit of work. The context is available for a caller that needs
// to pass request-scoped state or observe cancellation in a later stage.
type Task func(context.Context) (string, error)
type indexedResult struct {
index int
value string
err error
}
// RunTwo starts both tasks before it waits for either result. Results are put
// back in input order, even when the second task finishes first. Both tasks
// are always collected; fail-fast cancellation is the subject of stage 07.
func RunTwo(ctx context.Context, first, second Task) ([2]string, error) {
var values [2]string
if ctx == nil {
return values, errors.New("context must not be nil")
}
if first == nil || second == nil {
return values, errors.New("both tasks are required")
}
tasks := [...]Task{first, second}
results := make(chan indexedResult, len(tasks))
for index, task := range tasks {
go func(index int, task Task) {
value, err := task(ctx)
results <- indexedResult{index: index, value: value, err: err}
}(index, task)
}
var firstErr error
for range tasks {
result := <-results
values[result.index] = result.value
if result.err != nil && firstErr == nil {
firstErr = result.err
}
}
return values, firstErr
}
func main() {
service := NewService(Catalog{"book": 2100, "shipping": 500})
price, err := service.Quote(context.Background(), "book")
if err != nil {
fmt.Println("quote failed:", err)
return
}
fmt.Printf("%s: %d cents\n", price.Item, price.Cents)
}