PPysolate SpineREAD THE CODE · UNDERSTAND THE SYSTEM
课程与章节
源码索引 / 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)
}