package main
import \"time\"
func main() {
i := 1
go func() {
for {
i++
}
}()
<-time.After(1 * time.Second)
prin
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?