在这个例子中,如果至少有一个程序发生错误,我们将取消所有正在运行的goroutine。为此,我们将使用sync 包中的errgroup。errgroup 是为作为子任务工作的一组goroutines的同步、错误传播和Context取消而创建的。
例子
我们将运行3个goroutine。如果其中任何一个延迟超过80毫秒才完成自己的工作,我们将强制它返回一个错误,因为我们很着急。如果发生这种情况,所有正在运行的goroutines也将被终止。否则,显然所有的工作都会顺利进行。
package main
import (
"context"
"fmt"
"math/rand"
"time"
"golang.org/x/sync/errgroup"
)
func main() {
fmt.Println(">> START")
// Prevent picking up the same random number all the time for sleeping.
rand.Seed(time.Now().UnixNano())
goErrGroup, ctx := errgroup.WithContext(context.Background())
goErrGroup.Go(func() error {
return doSomething(ctx, 1)
})
goErrGroup.Go(func() error {
return doSomething(ctx, 2)
})
goErrGroup.Go(func() error {
return doSomething(ctx, 3)
})
goErrGroup.Go(func() error {
return doSomething(ctx, 4)
})
// Wait for the first error from any goroutine.
if err:= goErrGroup.Wait(); err != nil {
fmt.Println(err)
}
fmt.Println(">> FINISH")
}
func doSomething(ctx context.Context, id int) error {
fmt.Printf("STR: gorotinne %d\n", id)
// Pick a random number to simulate time it takes to finish the job.
delay := rand.Intn(100)
if delay > 80 {
return fmt.Errorf("FAIL: gorotinne %d: %dms", id, delay)
}
time.Sleep(time.Duration(delay) * time.Millisecond)
fmt.Printf("END: gorotinne %d\n", id)
return nil
}
测试
在这个例子中,所有的goroutines都设法完成了它们正在做的事情:
>> START
STR: gorotinne 1
STR: gorotinne 2
STR: gorotinne 4
STR: gorotinne 3
END: gorotinne 3
END: gorotinne 1
END: gorotinne 4
END: gorotinne 2
>> FINISH
在这个例子中,只有goroutine 1和4成功地完成了他们正在做的事情:
>> START
STR: gorotinne 1
STR: gorotinne 2
STR: gorotinne 3
STR: gorotinne 4
END: gorotinne 1
END: gorotinne 4
FAIL: gorotinne 2: 99ms
>> FINISH
这个例子在一开始就失败了,所以没有一个goroutine有机会完成他们正在做的事情:
>> START
STR: gorotinne 1
STR: gorotinne 2
STR: gorotinne 3
STR: gorotinne 4
FAIL: gorotinne 1: 81ms
>> FINISH