Ini mungkin ulasan terakhir saya tentang pengendalian ralat semasa pergi. Saya rasa ini adalah yang terbaik juga. Kami tahu setiap arahan yang kami laksanakan adalah dalam konteks. Dan konteks boleh mempunyai ralat. Pada masa inilah saya berfikir mengapa tidak hanya membuat pembalut di atas konteks semasa. Jadi, semua tugas jika dilaksanakan melalui fn tertentu maka kita mungkin boleh menyemak sama ada ctx mempunyai ralat dan jika ya jangan laksanakan lain laksanakan dan kumpulkan ralat. Ini mungkin menjadi anti-corak tetapi ya sehingga ia menjadi, kita boleh cuba bermain-main.
Nah, kursor mempunyai beberapa perkara untuk ditambahkan ->
Pertimbangkan cabaran biasa ini apabila menangani tugasan serentak:
Mari bina TaskContext yang menyelesaikan masalah ini:
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.AddError(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) { // ... similar to RunParallel but with semaphore ... sem := make(chan struct{}, limit) // ... implementation ... }
func ExampleTaskContext_ShipmentProcessing() { ctx := goctx.NewTaskContext(context.Background()) order := dummyOrder() shipment := dummyShipment() // Step 1: Validate address // Step 2: Calculate shipping cost // Step 3: Generate label _ = goctx.Run(ctx, validateAddress("123 Main St")) cost := goctx.Run(ctx, calculateShipping(order)) trackingNum := goctx.Run(ctx, generateLabel(shipment.OrderID, cost)) if ctx.Err() != nil { fmt.Printf("Error: %v\n", ctx.Err()) return } shipment.Status = "READY" shipment.TrackingNum = trackingNum fmt.Printf("Shipment processed: %+v\n", shipment) // Output: // Shipment processed: {OrderID:ORD123 Status:READY TrackingNum:TRACK-ORD123-1234567890} }
func ExampleTaskContext_OrderProcessing() { ctx := goctx.NewTaskContext(context.Background()) // Mock order order := []OrderItem{ {ProductID: "LAPTOP", Quantity: 2}, {ProductID: "MOUSE", Quantity: 3}, } taskCtx := goctx.NewTaskContext(ctx) // Create inventory checks for each item inventoryChecks := goctx.Run[[]goctx.RunFn[bool]](taskCtx, func() ([]goctx.RunFn[bool], error) { return streams.NewTransformer[OrderItem, goctx.RunFn[bool]](order). Transform(streams.MapItSimple(checkInventory)). Result() }) // Run inventory checks in parallel _, err := goctx.RunParallel(ctx, inventoryChecks...) fmt.Printf("Inventory check error: %v\n", err) // Output: // Inventory check error: task 1: insufficient inventory for LAPTOP }
Berikut ialah cara untuk menguji pelaksanaan:
func TestTaskContext(t *testing.T) { t.Run("handles parallel errors", func(t *testing.T) { ctx := NewTaskContext(context.Background()) _, err := RunParallel(ctx, func() (int, error) { return 0, errors.New("error 1") }, func() (int, error) { return 0, errors.New("error 2") }, ) assert.Error(t, err) assert.Contains(t, err.Error(), "error 1") assert.Contains(t, err.Error(), "error 2") }) }
Pelaksanaan TaskContext ini menyediakan penyelesaian yang mantap untuk mengendalikan pelaksanaan tugas serentak dengan pengendalian ralat yang betul dalam Go. Ia amat berguna apabila anda perlu:
Kod lengkap tersedia di GitHub.
Apakah corak yang anda gunakan untuk mengendalikan pelaksanaan tugas serentak dalam Go? Kongsi pendapat anda dalam komen di bawah!
Atas ialah kandungan terperinci Membina Konteks Pelaksanaan Tugas yang Teguh dalam Go. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!