本文介绍一种在 Go 语言中进行更优雅的错误处理方法,尤其适用于并发任务场景。核心思想是在现有上下文基础上构建一个包装器,以便集中管理和处理任务执行过程中的错误。
挑战与解决方案
并发任务处理常常面临以下挑战:
为此,我们构建了一个 taskcontext 来应对这些挑战:
package taskctx import ( "context" "errors" "fmt" "sync" ) type runfn[T any] func() (T, error) type taskcontext struct { context.Context mu sync.RWMutex err error multierr []error } func newtaskcontext(parent context.Context) *taskcontext { if parent == nil { panic("cannot create context from nil parent") } return &taskcontext{Context: parent} }
关键特性
func (c *taskcontext) witherror(err error) *taskcontext { if err == nil { return c } c.mu.Lock() defer c.mu.Unlock() c.multierr = append(c.multierr, err) if c.err == nil { c.err = err } else { c.err = errors.Join(c.err, err) } return c }
func run[T any](ctx *taskcontext, fn runfn[T]) T { var zero T if err := ctx.Err(); err != nil { return zero } result, err := fn() if err != nil { ctx.witherror(err) return zero } return result }
func runparallel[T any](ctx *taskcontext, fns ...func() (T, error)) ([]T, error) { if err := ctx.Err(); err != nil { return nil, err } results := make([]T, len(fns)) var resultsmu sync.Mutex var wg sync.WaitGroup wg.Add(len(fns)) for i, fn := range fns { i, fn := i, fn go func() { defer wg.Done() result, err := fn() if err != nil { ctx.witherror(fmt.Errorf("task %d: %w", i+1, err)) } else { resultsmu.Lock() results[i] = result resultsmu.Unlock() } }() } wg.Wait() return results, ctx.errors() }
func runparallelwithlimit[T any](ctx *taskcontext, limit int, fns ...func() (T, error)) ([]T, error) { // ... 使用信号量实现受限并发 ... }
使用示例
// ... (示例代码略,与原文类似) ...
// ... (示例代码略,与原文类似) ...
优势
测试
// ... (测试代码略,与原文类似) ...
总结
taskcontext 提供了一种在 Go 中高效处理并发任务执行和错误管理的方案,尤其适用于需要同时执行多个任务、收集所有错误、限制并发度以及保证线程安全的场景。 完整代码可在 Github 上获取。(此处需补充Github链接,如果原文提供的话)
讨论
您在 Go 中是如何处理并发任务执行和错误处理的?欢迎在评论区分享您的经验和想法!
(联系方式与原文保持一致)
以上就是在 Go 中构建健壮的任务执行上下文的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号