Rumah  >  Artikel  >  pembangunan bahagian belakang  >  Pergi program keluar sebelum kerja goroutine selesai

Pergi program keluar sebelum kerja goroutine selesai

PHPz
PHPzke hadapan
2024-02-08 22:57:20843semak imbas

Go 程序在 goroutine 工作完成之前退出

Dalam artikel ini, editor php Xiaoxin akan memperkenalkan isu penting tentang program Go: situasi keluar sebelum kerja goroutine selesai. Dalam bahasa Go, goroutine ialah utas ringan yang boleh melaksanakan tugas secara serentak. Walau bagaimanapun, apabila program kami mungkin keluar sebelum kerja goroutine selesai, kami perlu memahami cara mengendalikan situasi ini untuk memastikan program kami dapat menyelesaikan tugas dengan betul. Dalam kandungan berikut, kami akan meneroka masalah ini dan menyediakan beberapa penyelesaian untuk menyelesaikannya.

Kandungan soalan

Saya menghadapi masalah memahami cara menyekat dan menutup saluran dengan betul. Saya memulakan bilangan pekerja yang sewenang-wenangnya dan saya mendapati bahawa fungsi utama saya sama ada keluar sebelum pekerja selesai atau terhenti disebabkan saluran yang tidak ditutup. Saya memerlukan cara yang lebih baik untuk menghalang pekerja daripada membaca saluran tanpa keluar dari saluran utama, dan kemudian menutup saluran dengan anggun apabila selesai untuk menamatkan gelung. Sebarang percubaan yang saya lakukan berakhir dengan kebuntuan.

Saya telah mencuba beberapa perkara, termasuk menggunakan kumpulan tunggu, tetapi masalah itu berterusan. Saya perasan bahawa dengan menambah time.sleep program berfungsi seperti yang diharapkan, tetapi mengulasnya menyebabkan tiada kerja dilakukan.

time.sleep(time.duration(10 * time.second))

Berikut ialah contoh yang berfungsi https://go.dev/play/p/qhqnj-ajqbi dengan sleep dipelihara. Ini ialah kod yang rosak dengan tamat masa tidur diulas.

package main

import (
    "fmt"
    "sync"
    "time"
)

// some complicated work
func do(num int, ch chan<- int) {
    time.sleep(time.duration(500 * time.millisecond))
    ch <- num
}

func main() {

    results := make(chan int)

    // for some number of required complicated work
    for i := 0; i < 53; i++ {
        go do(i, results)
    }

    var wg sync.waitgroup

    // start 3 workers which can process results
    for i := 0; i < 3; i++ {
        wg.add(1)
        go func(id int) {
            defer wg.done()
            worker(id, results)
        }(i)
    }

    // handle closing the channel when all workers complete
    go func() {
        wg.wait()
        close(results)
    }()

    //time.sleep(time.duration(10 * time.second))

    fmt.println("donezo")
}

// process the results of do() in a meaningful way
func worker(id int, ch <-chan int) {
    fmt.println("starting worker", id)

    for i := range ch {
        fmt.println("channel val:", i)
    }
}

Saya juga cuba meletakkan defer wg.done() 移动到 worker() di dalam func tetapi ia adalah masalah yang sama dan tidak berfungsi tanpa tidur.

// process the results of do() in a meaningful way
func worker(wg *sync.WaitGroup, id int, ch <-chan int) {
    fmt.Println("starting worker", id)

    defer wg.Done()

    for i := range ch {
        fmt.Println("channel val:", i)
    }
}

Adakah saya memilih paradigma yang salah, atau saya hanya menggunakan paradigma yang salah? .

Saya terpaksa mempelajari konsep asas yang menarik tentang saluran: anda boleh membaca data daripada saluran tertutup, iaitu mengalirkan saluran. Seperti yang dinyatakan dalam contoh asal saya

tidak pernah ditamatkan kerana saya tidak dapat mencari tempat yang baik untuk menutup saluran, dan walaupun saya memaksanya dengan cara kreatif lain, program itu menunjukkan tingkah laku yang buruk

Keluar tanpa memproses semua kandungan dalam saluran

Kebuntuan atau penghantaran pada saluran tertutuprange

    Ini disebabkan oleh perbezaan halus dalam kod "
  • sebenar
  • ", di mana masa yang diperlukan untuk memproses kandungan saluran
  • lebih lama daripada masa yang diperlukan untuk mengisi

saluran dan perkara tidak segerak. Memandangkan tiada cara praktikal yang jelas dalam penghantar saya untuk menutup saluran (yang disyorkan dalam 99% tutorial saluran), apabila anda mempunyai beberapa pekerja membaca saluran dan pekerja tidak mengetahuinya, dengan goroutine dalam Ia adalah sebenarnya boleh diterima untuk melakukan ini di utama di mana nilai terakhir dibaca. Penyelesaian Saya membungkus pekerja itu dalam sync.waitgroupnya sendiri dan menggunakan worker.wait() untuk

mencegah

program daripada keluar, membenarkan kerja "selesai" ". Apabila tiada lagi data untuk dihantar, saya menutup() saluran secara bebas, iaitu saya menyekat dengan menunggu penulis selesai menggunakan kumpulan tunggu mereka sendiri. close menyediakan penamatan untuk kes gelung julat , kerana apabila nilai lalai saluran dikembalikan, iaitu jenis eof dikembalikan apabila penghujung saluran dicapai, ia akan berakhir menyekat saluran persimpangan sehingga ia ditutup

.

Pandangan saya mengenai ini ialah jika anda tidak tahu berapa banyak nilai yang akan ditolak secara selari, go tidak mempunyai cara untuk mengetahui panjang saluran yang tidak dibuffer kerana ia berada dalam skop, sync.waitgroup 中,并使用 worker.wait()阻止程序退出,从而允许工作“完成” ”。当没有更多数据要发送时,我独立地 close()sehingga anda menutupnya.

. Memandangkan ia ditutup, ini bermakna membaca apa sahaja yang tinggal sehingga nilai penamatan atau tamat.

akan disekat sehingga selesai. Contoh operasi yang diselesaikan workers.wait()https://www.php.cn/link/2bf0ccdbb4d3ebbcb990af74bd78c658

Contoh membaca saluran tertutup https://www.php.cn/link/d5397f1497b5cdaad7253fdc92db610b

Output

filling 0
filling 1
filling 2
filling 3
filling 4
filling 5
filling 6
filling 7
filling 8
filling 9
closed
empyting 0
empyting 1
empyting 2
empyting 3
empyting 4
empyting 5
empyting 6
empyting 7
empyting 8
empyting 9

Atas ialah kandungan terperinci Pergi program keluar sebelum kerja goroutine selesai. 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