In der Go-Sprache kann Goroutine verwendet werden, um Aufgaben gleichzeitig auszuführen, und sync.WaitGroup ist ein Synchronisationsmechanismus, der verwendet wird, um auf den Abschluss einer Gruppe von Goroutinen zu warten. Der PHP-Editor Banana hat jedoch festgestellt, dass die Verwendung von Goroutine mit sync.WaitGroup in einigen Fällen zu inkonsistenten Ergebnissen führen kann. Dieses Problem tritt normalerweise auf, wenn mehrere Goroutinen gleichzeitig gemeinsam genutzte Variablen ändern. Da die Ausführungsreihenfolge von Goroutinen unsicher ist, kann es zu Inkonsistenzen in den Endergebnissen kommen. In diesem Artikel werden wir die Ursachen dieses Problems untersuchen und einige Lösungen bereitstellen, um die Ergebniskonsistenz zwischen Goroutinen sicherzustellen.
Ich versuche, Goroutine (in Go-Sprache) zu verwenden, um die Anzahl der Primzahlen zu zählen, die kleiner als jede ganze Zahl sind i
.
Wenn i
为 100,则结果应为 25
beispielsweise 100 ist, sollte das Ergebnis 25
sein.
Hier ist meine aktuelle Implementierung:
<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>
Wenn ich dieses Programm ausführe, erhalte ich korrekte Ergebnisse für kleinere i
Werte (bis etwa 1000)
Aber bei größeren i
Werten sind die Ergebnisse inkonsistent und falsch.
❯ ./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
Je größer der Wert von i
的值变大,结果波动增大。是什么原因造成的?有什么方法可以使其一致且正确吗?
您有一个共享变量,但没有适当的同步。存在竞争条件(*pr += 1
)。在共享变量前后添加互斥体修复它(mu.Lock()、mu.Unlock()
wird, desto größer wird die Ergebnisschwankung. Was verursacht das? Gibt es eine Möglichkeit, es konsistent und korrekt zu machen?
Workaround
Sie haben eine gemeinsam genutzte Variable, aber keine ordnungsgemäße Synchronisierung. Es liegt eine Racebedingung vor (*pr += 1
). Das Hinzufügen von Mutexes vor und nach der gemeinsam genutzten Variablen behebt das Problem (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
Das obige ist der detaillierte Inhalt vonDie Verwendung von Goroutine mit sync.WaitGroup führt zu inkonsistenten Ergebnissen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!