Menggunakan errgroup untuk melaksanakan kumpulan kerja Go, gorouti terperangkap

王林
Lepaskan: 2024-02-08 21:09:18
ke hadapan
981 orang telah melayarinya

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

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

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

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

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

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

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!

sumber:stackoverflow.com
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
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan
Tentang kita Penafian Sitemap
Laman web PHP Cina:Latihan PHP dalam talian kebajikan awam,Bantu pelajar PHP berkembang dengan cepat!