Rumah  >  Artikel  >  pembangunan bahagian belakang  >  Goroutine dipanggil secara rekursif mengikut masa. AfterFunc() direka dengan buruk

Goroutine dipanggil secara rekursif mengikut masa. AfterFunc() direka dengan buruk

WBOY
WBOYke hadapan
2024-02-09 13:48:21817semak imbas

由 time.AfterFunc() 递归调用的 goroutine 的设计很糟糕

Editor PHP Xigua percaya bahawa ayat "Reka bentuk goroutine dipanggil secara rekursif mengikut masa. AfterFunc() sangat teruk" menggambarkan idea reka bentuk yang tidak munasabah. Dalam pengaturcaraan serentak, memanggil goroutine secara rekursif boleh menyebabkan penggunaan sumber yang berlebihan dan juga menyebabkan masalah seperti kebuntuan dan limpahan memori. Oleh itu, panggilan rekursif harus digunakan dengan berhati-hati dan alternatif lain untuk menyelesaikan masalah harus dipertimbangkan untuk memastikan prestasi dan kestabilan program. Apabila menulis kod, kita harus sentiasa memberi perhatian kepada kerasionalan reka bentuk untuk mengelakkan masalah yang tidak perlu.

Kandungan soalan

Saya mempunyai aplikasi http kecil (A). Semasa permulaan, ia memanggil perkhidmatan http lain (B) untuk mengesahkan lesen dan jika lesen itu OK, pelayan http (A) bermula. Jika pengesahan gagal A, ralat maut akan berlaku dan keluar

Semakan lesen dijalankan setiap 24 jam

Adakah ia akan dianggap reka bentuk yang buruk untuk mencipta goroutin baharu secara rekursif setiap 24 jam? Semak kod saya di bawah. Adakah goroutine sebelumnya akan ditutup atau terus berjalan, dan kemudian n goroutine akan memanggil satu sama lain dan berakhir?

Adakah setiap goroutine baru dipanggil dari goroutine utama atau dari goroutine kanak-kanak?

Modul pengesahan lesen. A Perkhidmatan Pemeriksaan B

func Request(retry bool) error {
    // request and verify license (external http service)
    err := verify_license()
    if err != nil {
        return err
    }
    
    if retry {
        //  Renew verification timeout (renew license every 24 hours)
        time.AfterFunc(LICENSE_TIMEOUT, func(){
            request_retry()
        })
    }
    
    return nil
}

func request_retry(){
    for i := 0; i < LICENSE_RETRY; i++ {
        if err := v.Request(false); err == nil {
            break
        }
        
        time.Sleep(LICENSE_RETRY_TIMEOUT)
    }
    
    time.Sleep(LICENSE_TIMEOUT)
    v.Request(true)
}

Dalam pakej utama sebelum pelayan HTTP (A) bermula

if err := license_verify.Request(true); err != nil {
    log.Fatal(err.Error())
}

Penyelesaian

Mungkin anda boleh memikirkan semula reka bentuk masalah. Contohnya:

func main() {
    if !checkLicense() {
        log.Fatal("license check failed")
    }

    srv := http.Server{} // 
    
    ctx, cancel := context.WithCancel(context.Background())
    defer cancel()
    go func() {
         for {
             select {
             case <-ctx.Done(): // in case you want to instal signal handlers etc
                  return
             case <-time.After(24 * time.Hour):
                  if !checkLicense() {
                      cancel() // or srv.Shtdown, really depends on you
                  }
             }
         }
    }()

    if err := srv.ListenAndServe(); err != nil {
        log.Fatal(err)
    }
}

func checkLicense() bool {
    // add retries per request here
}

Pada asasnya, apa yang ia lakukan ialah mencipta goroutine yang menyemak secara berkala dan memberitahu konteks atau saluran jika berlaku kesilapan.

Jika saya faham soalan dengan betul, anda hanya perlu ringkaskan sahaja. Satu blok bangunan adalah untuk mencuba semula permintaan jika ia gagal. Jika tidak, terdapat percubaan semula 24 jam. Lapisan terakhir adalah untuk bertindak balas terhadap pemeriksaan jika ia gagal. Anda boleh menggunakan konteks, saluran atau apa sahaja yang anda suka

Atas ialah kandungan terperinci Goroutine dipanggil secara rekursif mengikut masa. AfterFunc() direka dengan buruk. 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