Rumah >pembangunan bahagian belakang >Golang >Menggunakan errgroup untuk melaksanakan kumpulan kerja Go, gorouti terperangkap

Menggunakan errgroup untuk melaksanakan kumpulan kerja Go, gorouti terperangkap

王林
王林ke hadapan
2024-02-08 21:09:181026semak imbas

使用 errgroup 实现 Go 工作池,goroutines 卡住

Editor PHP Apple hari ini memperkenalkan anda kepada kaedah menggunakan errgroup untuk melaksanakan kumpulan Go work, yang menyelesaikan masalah goroutine tersekat. Dalam pengaturcaraan serentak, pemprosesan serentak yang cekap boleh dicapai dengan menggunakan goroutine, tetapi apabila ralat atau tersekat berlaku dalam goroutine tertentu, ia akan menjejaskan pelaksanaan keseluruhan program. Dengan menggunakan pakej errgroup, kami boleh menguruskan perlaksanaan goroutine secara elegan dan mengendalikan ralat apabila ralat berlaku, memastikan kestabilan dan kebolehpercayaan program. Mari kita lihat bagaimana ini dilaksanakan.

Kandungan soalan


Saya telah melaksanakan pola kumpulan pekerja menggunakan errgroup supaya ralat dalam mana-mana goroutine dapat ditangkap. Berikut adalah butiran saya:

jobs := make(chan usersinfo, totalusers)
    results := make(chan usersinfo, totalusers)

    g, gctx := errgroup.withcontext(ctx)

    for i := 1; i <= 4; i++ {
        g.go(func() error {
            err := workeruser(gctx, jobs, results)
            if err != nil {
                return err
            }
            return nil
        })
    }

    for _, user := range usersresp {
        jobs <- user
    }
    close(jobs)

    var usersarray []usersinfo
    for  i := 1; i <= totalusers; i++ {
        r := <-results
        usersarray = append(usersarray, r)
    }

    if err := g.wait(); err != nil {
        return nil, err
    }

Maka pelaksanaan fungsi pekerja adalah seperti berikut:

func workerUser(ctx context.Context, jobs <-chan UsersInfo, results chan<- UsersInfo) error {
  for {
    select {
    case <-ctx.Done():
        return ctx.Err()
    case user, _ := <-jobs:
        userInfo, err := CallUserAPI(ctx, user)
        if err != nil {
            return err
        }
        results <- userInfo
    }
 }
}

calluserapi mengembalikan ralat terlarang 403, yang sepatutnya memanggil g.wait() dan harus menghentikan semua goroutine serta-merta pada ralat bukan nol. Tetapi itu tidak berlaku di sini, g.wait() tidak pernah dipanggil.


Penyelesaian


Ada beberapa masalah:

  • Gelung

    for  i := 1; i <= totalusers; i++ {
          r := <-results
          usersarray = append(usersarray, r)
      }

    Tunggu kakitangan menghantar keputusan untuk setiap pengguna. Ini tidak berlaku apabila calluserapi mengembalikan ralat.

  • pekerja tidak mengendalikan jobssituasi tertutup.

Kod berikut boleh menyelesaikan dua masalah ini:

Isytiharkan jenis, nyatakan pengguna mana yang hendak diproses dan tempat untuk meletakkan hasilnya:

type job struct {
    user usersinfo
    result *usersinfo
}

Ubah suai urutan pekerja untuk menggunakan jenis baharu ini. Selain itu, ubah suai pekerja supaya ia keluar apabila jobs ditutup.

func workeruser(ctx context.context, jobs <-chan job) error {
    for {
        select {
        case <-ctx.done():
            return ctx.err()
        case job, ok := <-jobs:
            if !ok {
                // no more jobs, exit.
                return nil
            }
            var err error
            *job.result, err = calluserapi(ctx, job.user)
            if err != nil {
                return err
            }
        }
    }
}

Lekatkan bersama dalam goroutine utama:

jobs := make(chan UsersInfo, totalUsers)
usersArray := make([]UsersInfo, totalUsers)
g, gCtx := errgroup.WithContext(ctx)

// Start the workers.
for i := 1; i <= 4; i++ {
    g.Go(func() error {
        return workerUser(gCtx, jobs)
    })
}

// Feed the workers.  
for i, user := range usersResp {
    jobs <- job{user: user, result: &usersArray[i]}
}

// Close the channel to indicate that no more jobs will be sent.
// The workers exit via the `if !ok { return nil }` statement.
close(jobs)

// Wait for the workers to complete.
if err := g.Wait(); err != nil {
    return nil, err
}

// It is now safe to access the results in usersArray.

Atas ialah kandungan terperinci Menggunakan errgroup untuk melaksanakan kumpulan kerja Go, gorouti terperangkap. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:stackoverflow.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam