Rumah > pembangunan bahagian belakang > Golang > Membina Konteks Pelaksanaan Tugas yang Teguh dalam Go

Membina Konteks Pelaksanaan Tugas yang Teguh dalam Go

Susan Sarandon
Lepaskan: 2025-01-01 01:02:10
asal
275 orang telah melayarinya

Building a Robust Task Execution Context in Go

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 ->

Masalahnya

Pertimbangkan cabaran biasa ini apabila menangani tugasan serentak:

  1. Mengumpul ralat daripada berbilang goroutine
  2. Mengekalkan keselamatan benang
  3. Menghadkan pelaksanaan serentak
  4. Memelihara ralat pertama semasa mengumpul semua ralat
  5. Corak pengendalian ralat bersih

Penyelesaian: TaskContext

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}
}
Salin selepas log masuk

Ciri-ciri Utama

1. Pengendalian Ralat Selamat Benang

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
}
Salin selepas log masuk

2. Perlaksanaan Tugas Tunggal

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
}
Salin selepas log masuk

3. Pelaksanaan Tugasan Selari

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()
}
Salin selepas log masuk

4. Concurrency Terkawal

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 ...
}
Salin selepas log masuk

Contoh Penggunaan

Perlaksanaan Tugasan Mudah

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}
}
Salin selepas log masuk

Pelaksanaan Tugasan Selari

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
}
Salin selepas log masuk

Faedah

  1. Keselamatan Benang: Semua operasi dilindungi oleh mutex
  2. Koleksi Ralat: Mengekalkan kedua-dua ralat pertama dan semua ralat
  3. Penyatuan Konteks: Berfungsi dengan pakej konteks Go
  4. Sokongan Generik: Berfungsi dengan mana-mana jenis pulangan
  5. Kawalan Concurrency: Sokongan terbina dalam untuk mengehadkan pelaksanaan selari

Menguji

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")
    })
}
Salin selepas log masuk

Kesimpulan

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:

  • Laksanakan berbilang tugas serentak
  • Kumpul ralat daripada semua tugasan
  • Hadkan pelaksanaan serentak
  • Kekalkan keselamatan benang
  • Jejaki ralat pertama semasa mengumpul semua ralat

Kod lengkap tersedia di GitHub.

Sumber

  • Pakej Konteks Go
  • Go Concurrency Corak
  • Ralat Pengendalian dalam Go

Apakah corak yang anda gunakan untuk mengendalikan pelaksanaan tugas serentak dalam Go? Kongsi pendapat anda dalam komen di bawah!

  • https://x.com/mahadev_k_
  • https://in.linkedin.com/in/mahadev-k-934520223

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!

sumber:dev.to
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Artikel terbaru oleh pengarang
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan