Heim  >  Artikel  >  Backend-Entwicklung  >  Die Verwendung von Goroutine mit sync.WaitGroup führt zu inkonsistenten Ergebnissen

Die Verwendung von Goroutine mit sync.WaitGroup führt zu inkonsistenten Ergebnissen

WBOY
WBOYnach vorne
2024-02-09 10:30:10961Durchsuche

Die Verwendung von Goroutine mit sync.WaitGroup führt zu inkonsistenten Ergebnissen

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.

Frageninhalt

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()).

🎜Code: 🎜
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")
}
🎜Ausgabe: 🎜
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!

Stellungnahme:
Dieser Artikel ist reproduziert unter:stackoverflow.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen