Maison  >  Article  >  développement back-end  >  L'utilisation de goroutine avec sync.WaitGroup donne des résultats incohérents

L'utilisation de goroutine avec sync.WaitGroup donne des résultats incohérents

WBOY
WBOYavant
2024-02-09 10:30:101020parcourir

Lutilisation de goroutine avec sync.WaitGroup donne des résultats incohérents

Dans le langage Go, goroutine peut être utilisé pour exécuter des tâches simultanément, et sync.WaitGroup est un mécanisme de synchronisation utilisé pour attendre la fin d'un groupe de goroutines. Cependant, l'éditeur PHP Banana a constaté que dans certains cas, l'utilisation de goroutine avec sync.WaitGroup peut conduire à des résultats incohérents. Ce problème se produit généralement lorsque plusieurs goroutines modifient des variables partagées en même temps. L'ordre d'exécution des goroutines étant incertain, cela peut entraîner une incohérence dans les résultats finaux. Dans cet article, nous explorerons les causes de ce problème et proposerons quelques solutions pour garantir la cohérence des résultats entre les goroutines.

Contenu de la question

J'essaie d'utiliser goroutine (en langage Go) pour compter le nombre de nombres premiers inférieurs à n'importe quel nombre entier i. Par exemple, si i 为 100,则结果应为 25 vaut 100, le résultat devrait être 25.

Voici ma mise en œuvre actuelle :

<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>

Lorsque j'exécute ce programme, j'obtiens des résultats corrects pour des valeurs i plus petites (jusqu'à environ 1000)

Mais pour les valeurs i plus grandes, les résultats sont incohérents et incorrects.

❯ ./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

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

解决方法

您有一个共享变量,但没有适当的同步。存在竞争条件(*pr += 1)。在共享变量前后添加互斥体修复它(mu.Lock()、mu.Unlock() augmente, la fluctuation du résultat augmente. Quelle est la cause de cela ? Existe-t-il un moyen de le rendre cohérent et correct ?

Solution

Vous avez une variable partagée mais pas de synchronisation appropriée. Une condition de concurrence critique existe (*pr += 1). L'ajout de mutex avant et après la variable partagée la corrige (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")
}
🎜Sortie : 🎜
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

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer