Is this because the go compiler optimized the code?

前端 未结 2 1971
孤街浪徒
孤街浪徒 2021-01-05 04:49
package main

import \"time\"

func main() {
    i := 1
    go func() {
        for {
            i++
        }
    }()
    <-time.After(1 * time.Second)
    prin         


        
2条回答
  •  清酒与你
    2021-01-05 05:20

    Concurrent access to the variable i need to be synchronized:

    synchronization is better done with channels or the facilities of the sync package. Share memory by communicating; don't communicate by sharing memory.

    ref: https://golang.org/pkg/sync/atomic/


    This is interesting, so I'm sharing my experiments:

    0- Your code using time.Sleep(1 * time.Second) (not recommended-not synchronized):

    package main
    
    import "time"
    
    func main() {
        i := 1
        go func() {
            for {
                i++
            }
        }()
        time.Sleep(1 * time.Second)
        println(i)
    }
    

    output:

    1
    

    1- Using i := new(int) (not recommended-not synchronized):

    package main
    
    import "time"
    
    func main() {
        i := new(int)
        go func() {
            for {
                *i++
            }
        }()
        time.Sleep(1 * time.Second)
        println(*i)
    }
    

    output(CPU: i7-7700K @ 4.2GHz):

    772252413
    

    2- Synchronizing using atomic.AddInt64(&i, 1)(Package atomic provides low-level atomic memory primitives useful for implementing synchronization algorithms):

    package main
    
    import (
        "sync/atomic"
        "time"
    )
    
    func main() {
        i := int64(1)
        go func() {
            for {
                atomic.AddInt64(&i, 1) // free running counter
            }
        }()
        time.Sleep(1 * time.Second)
        println(atomic.LoadInt64(&i)) // sampling the counter
    }
    

    output:

    233008800
    

    3- Synchronizing using chan int:

    package main
    
    import "time"
    
    func main() {
        ch := make(chan int)
        go func() {
            timeout := time.NewTimer(1 * time.Second)
            defer timeout.Stop()
            i := 1
            for {
                select {
                case <-timeout.C:
                    ch <- i
                    return
                default:
                    i++
                }
            }
        }()
        //time.Sleep(1 * time.Second)
        println(<-ch)
    }
    

    output:

    272702341
    

    4- Synchronizing using sync.WaitGroup:

    package main
    
    import (
        "fmt"
        "sync"
        "time"
    )
    
    func main() {
        var done sync.WaitGroup
        done.Add(1)
        i := 1
        go func() {
            defer done.Done()
            timeout := time.NewTimer(1 * time.Second)
            defer timeout.Stop()
            for {
                select {
                case <-timeout.C:
                    return
                default:
                    i++
                }
            }
        }()
        done.Wait()
        fmt.Println(i)
    }
    

    output:

    261459418
    

    5- Synchronizing using quit channel:

    package main
    
    import (
        "fmt"
        "time"
    )
    
    func main() {
        quit := make(chan struct{})
        i := 1
        go func() {
            for {
                i++
                select {
                case <-quit:
                    return
                default:
                }
            }
        }()
        time.Sleep(1 * time.Second)
        quit <- struct{}{}
        fmt.Println(i)
    }
    

    output:

    277366276
    

    6- Synchronizing using sync.RWMutex:

    package main
    
    import (
        "sync"
        "time"
    )
    
    func main() {
        var i rwm
        go func() {
            for {
                i.inc() // free running counter
            }
        }()
        time.Sleep(1 * time.Second)
        println(i.read()) // sampling the counter
    }
    
    type rwm struct {
        sync.RWMutex
        i int
    }
    
    func (l *rwm) inc() {
        l.Lock()
        defer l.Unlock()
        l.i++
    }
    func (l *rwm) read() int {
        l.RLock()
        defer l.RUnlock()
        return l.i
    }
    

    output:

    24271318
    

    related topics:

    The Go Memory Model
    There is no equivalent to volatile and register in Go
    Does Go support volatile / non-volatile variables?

提交回复
热议问题