Menggunakan goroutine dengan penyegerakan.WaitGroup menghasilkan keputusan yang tidak konsisten

WBOY
Lepaskan: 2024-02-09 10:30:10
ke hadapan
1020 orang telah melayarinya

Menggunakan goroutine dengan penyegerakan.WaitGroup menghasilkan keputusan yang tidak konsisten

Dalam bahasa Go, goroutine boleh digunakan untuk melaksanakan tugas secara serentak dan menyegerakkan.WaitGroup ialah mekanisme penyegerakan yang digunakan untuk menunggu selesainya kumpulan goroutin. Walau bagaimanapun, Editor PHP Banana mendapati bahawa dalam beberapa kes, menggunakan goroutine dengan penyegerakan.WaitGroup boleh membawa kepada hasil yang tidak konsisten. Masalah ini biasanya berlaku apabila berbilang goroutin mengubah suai pembolehubah yang dikongsi pada masa yang sama Memandangkan susunan pelaksanaan goroutin tidak pasti, ia mungkin membawa kepada ketidakkonsistenan dalam keputusan akhir. Dalam artikel ini, kami akan meneroka punca masalah ini dan menyediakan beberapa penyelesaian untuk memastikan konsistensi hasil antara goroutine.

Kandungan soalan

Saya cuba menggunakan goroutine (dalam Go lang) untuk mengira bilangan nombor perdana kurang daripada sebarang integer i. Contohnya, jika i 为 100,则结果应为 25 ialah 100, hasilnya hendaklah 25.

Berikut ialah pelaksanaan semasa saya:

<code>package "main"

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

var wg sync.WaitGroup

func isprime(x int) bool {
    if x == 2 {
        return true
    }
    if x == 1 || x%2 == 0 {
        return false
    }
    var xi = float64(x)
    for i := 3; float64(i) < (math.Pow(xi, 0.5) + 1.0); i += 2.0 {
        if x%i == 0 {
            return false
        }
    }
    return true
}

func main() {
    fmt.Print("Till what number should I count primes? ")
    var i int
    fmt.Scan(&i)

    r := 0
    pr := &r
    fmt.Println("Counting primes till ", i)
    start := time.Now()
    for x := 0; x <= i; x++ {
        wg.Add(1)
        go func(n int) {
            defer wg.Done()
            if isprime(n) {
                *pr += 1
            }
        }(x)
    }
    wg.Wait()
    elapsed := time.Since(start).Seconds()
    fmt.Println("Counted", r, "primes")
    fmt.Println("took", elapsed, "seconds")
}
</code>
Salin selepas log masuk

Apabila saya menjalankan program ini, saya mendapat hasil yang betul untuk nilai i yang lebih kecil (sehingga kira-kira 1000)

Tetapi untuk nilai i yang lebih besar, hasilnya tidak konsisten dan tidak betul.

❯ ./main
Till what number should I count primes? 10000
Counting primes till  10000
Counted 1228 primes
took 0.006776541 seconds
❯ ./main
Till what number should I count primes? 10000
Counting primes till  10000
Counted 1227 primes
took 0.004183875 seconds
❯ ./main
Till what number should I count primes? 1000000
Counting primes till  1000000
Counted 78254 primes
took 0.441985921 seconds
❯ ./main
Till what number should I count primes? 1000000
Counting primes till  1000000
Counted 78327 primes
took 0.430042047 seconds
Salin selepas log masuk

Apabila nilai i 的值变大,结果波动增大。是什么原因造成的?有什么方法可以使其一致且正确吗?

解决方法

您有一个共享变量,但没有适当的同步。存在竞争条件(*pr += 1)。在共享变量前后添加互斥体修复它(mu.Lock()、mu.Unlock() menjadi lebih besar, turun naik hasil meningkat. Apa yang menyebabkan ini? Adakah terdapat cara untuk menjadikannya konsisten dan betul?

Penyelesaian

Anda mempunyai pembolehubah dikongsi tetapi tiada penyegerakan yang betul. Keadaan perlumbaan wujud (*pr += 1). Menambah mutexes sebelum dan selepas pembolehubah kongsi membetulkannya (mu.Lock(), mu.Unlock()).

🎜Kod: 🎜
var wg sync.WaitGroup
var mu sync.Mutex

func main() {
    fmt.Print("Till what number should I count primes? ")
    var i int
    fmt.Scan(&i)

    r := 0
    pr := &r
    fmt.Println("Counting primes till ", i)
    start := time.Now()
    for x := 0; x <= i; x++ {
        wg.Add(1)
        go func(n int) {
            defer wg.Done()
            if isprime(n) {
                mu.Lock()   // <= lock
                *pr += 1
                mu.Unlock()  // <= unlock
            }
        }(x)
    }
    wg.Wait()
    elapsed := time.Since(start).Seconds()
    fmt.Println("Counted", r, "primes")
    fmt.Println("took", elapsed, "seconds")
}
Salin selepas log masuk
🎜Keluaran: 🎜
Till what number should I count primes? 1000000
Counting primes till  1000000
Counted 78498 primes
took 0.6783484 seconds
Till what number should I count primes? 1000000
Counting primes till  1000000
Counted 78498 primes
took 0.5428273 seconds
Till what number should I count primes? 1000000
Counting primes till  1000000
Counted 78498 primes
took 0.5521617 seconds
Salin selepas log masuk

Atas ialah kandungan terperinci Menggunakan goroutine dengan penyegerakan.WaitGroup menghasilkan keputusan yang tidak konsisten. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Label berkaitan:
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