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.
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>
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
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()
).
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") }
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
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!