Using goroutine with sync.WaitGroup results in inconsistent results

WBOY
Release: 2024-02-09 10:30:10
forward
1010 people have browsed it

Using goroutine with sync.WaitGroup results in inconsistent results

In the Go language, goroutine can be used to execute tasks concurrently, and sync.WaitGroup is a synchronization mechanism used to wait for the completion of a group of goroutines. However, PHP Editor Banana found that in some cases, using goroutine with sync.WaitGroup may lead to inconsistent results. This problem usually occurs when multiple goroutines modify shared variables at the same time. Since the execution order of goroutines is uncertain, it may lead to inconsistency in the final results. In this article, we will explore the causes of this problem and provide some solutions to ensure result consistency between goroutines.

Question content

I am trying to use goroutine (in Go lang) to count the number of prime numbers less than an arbitrary integer i. For example, if i is 100, the result should be 25.

The following is my current implementation:

<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>
Copy after login

When I run this program, I get correct results for smaller i values ​​(up to about 1000)

But for larger i values, the results are inconsistent and incorrect.

❯ ./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
Copy after login

As the value of i becomes larger, the result fluctuation increases. What causes this? Is there any way to make it consistent and correct?

Workaround

You have a shared variable without proper synchronization. A race condition exists (*pr = 1). Adding mutexes before and after the shared variable fixes it (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")
}
Copy after login

Output:

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
Copy after login

The above is the detailed content of Using goroutine with sync.WaitGroup results in inconsistent results. For more information, please follow other related articles on the PHP Chinese website!

source:stackoverflow.com
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!