package main
import "time"
func main() {
i := 1
go func() {
for {
i++
}
}()
<-time.After(1 * time.Second)
println(i)
}
The output is always 1.
However it's absolutely that 1s is enough for the for loop to go over many many times.
I think the i in the closure is the i in the main func.
See the code below.
package main
import "time"
func main() {
i := 1
go func() {
for {
i++
println("+1")
}
}()
<-time.After(1 * time.Second)
println(i)
}
After many lines of "+1", the output is exactly a great number as expected.
The Go Memory Model
Version of May 31, 2014
Introduction
The Go memory model specifies the conditions under which reads of a
variable in one goroutine can be guaranteed to observe values produced
by writes to the same variable in a different goroutine.
Advice
Programs that modify data being simultaneously accessed by multiple
goroutines must serialize such access.
To serialize access, protect the data with channel operations or other
synchronization primitives such as those in the sync and sync/atomic
packages.
If you must read the rest of this document to understand the behavior
of your program, you are being too clever.
Don't be clever.
Synchronization
var a string
func hello() {
go func() { a = "hello" }()
print(a)
}
the assignment to a is not followed by any synchronization event, so
it is not guaranteed to be observed by any other goroutine. In fact,
an aggressive compiler might delete the entire go statement.
The assignment to i, via increment i++ (i = i + 1), is not followed by any synchronization event, so it is not guaranteed to be observed by any other goroutine. In fact, an aggressive compiler might delete the entire i++ statement.
For example,
package main
import "time"
func main() {
i := 1
go func() {
for {
i++
}
}()
<-time.After(1 * time.Millisecond)
println(i)
}
Output:
1
The goroutine reduces to:
"".main.func1 STEXT nosplit size=2 args=0x8 locals=0x0
0x0000 00000 (elide.go:7) TEXT "".main.func1(SB), NOSPLIT, $0-8
0x0000 00000 (elide.go:7) FUNCDATA $0, gclocals·2a5305abe05176240e61b8620e19a815(SB)
0x0000 00000 (elide.go:7) FUNCDATA $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
0x0000 00000 (elide.go:9) JMP 0
To the compiler,
for {
i++
}
can be implemented by incrementing a register forever, essentially a no-op for loop.
for { }
After inserting a print statement,
package main
import "time"
func main() {
i := 1
go func() {
for {
i++
println("+1")
}
}()
<-time.After(1 * time.Millisecond)
println(i)
}
Output:
+1
+1
<< SNIP >>
+1
+1
432
The goroutine expands to,
"".main.func1 STEXT size=81 args=0x8 locals=0x18
0x0000 00000 (elide.go:7) TEXT "".main.func1(SB), $24-8
0x0000 00000 (elide.go:7) MOVQ (TLS), CX
0x0009 00009 (elide.go:7) CMPQ SP, 16(CX)
0x000d 00013 (elide.go:7) JLS 74
0x000f 00015 (elide.go:7) SUBQ $24, SP
0x0013 00019 (elide.go:7) MOVQ BP, 16(SP)
0x0018 00024 (elide.go:7) LEAQ 16(SP), BP
0x001d 00029 (elide.go:7) FUNCDATA $0, gclocals·a36216b97439c93dafebe03e7f0808b5(SB)
0x001d 00029 (elide.go:7) FUNCDATA $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
0x001d 00029 (elide.go:8) MOVQ "".&i+32(SP), AX
0x0022 00034 (elide.go:9) INCQ (AX)
0x0025 00037 (elide.go:10) PCDATA $0, $0
0x0025 00037 (elide.go:10) CALL runtime.printlock(SB)
0x002a 00042 (elide.go:10) LEAQ go.string."+1\n"(SB), AX
0x0031 00049 (elide.go:10) MOVQ AX, (SP)
0x0035 00053 (elide.go:10) MOVQ $3, 8(SP)
0x003e 00062 (elide.go:10) PCDATA $0, $0
0x003e 00062 (elide.go:10) CALL runtime.printstring(SB)
0x0043 00067 (elide.go:10) PCDATA $0, $0
0x0043 00067 (elide.go:10) CALL runtime.printunlock(SB)
0x0048 00072 (elide.go:9) JMP 29
0x004a 00074 (elide.go:9) NOP
0x004a 00074 (elide.go:7) PCDATA $0, $-1
0x004a 00074 (elide.go:7) CALL runtime.morestack_noctxt(SB)
0x004f 00079 (elide.go:7) JMP 0
The increased complexity of the goroutine means that the compiler no longer considers dedicating a register to the value of i. The in-memory value of i is incremented, which makes the updates visible, with a data race, to the main goroutine.
==================
WARNING: DATA RACE
Read at 0x00c420094000 by
main goroutine:
main.main()
/home/peter/gopath/src/lucky.go:14 +0xac
Previous write at 0x00c420094000 by
goroutine 5:
main.main.func1()
/home/peter/gopath/src/lucky.go:9 +0x4e
Goroutine 5 (running) created at:
main.main()
/home/peter/gopath/src/lucky.go:7 +0x7a
==================
For your expected result, add some synchronization,
package main
import (
"sync"
"time"
)
func main() {
mx := new(sync.Mutex)
i := 1
go func() {
for {
mx.Lock()
i++
mx.Unlock()
}
}()
<-time.After(1 * time.Second)
mx.Lock()
println(i)
mx.Unlock()
}
Output:
41807838
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?
Related
I have the following code https://play.golang.org/p/9jPlypO4d-
package main
import (
"fmt"
"sync"
"time"
)
func main() {
var wg sync.WaitGroup
wg.Add(1)
c := make(chan int)
go func() {
defer wg.Done()
for {
if <-c == -1 {
fmt.Print(":")
return
}
fmt.Print(".")
time.Sleep(time.Second)
}
}()
c <- 0
time.Sleep(time.Second * 5)
c <- -1
wg.Wait()
}
I wonder why there is only one . printed? Shouldn't it be like 4 or 5?
if <-c == -1 will block until there is something in the channel. So, the first value is 0, it gets it, prints out a ., sleeps one second (while outside the goroutine it is sleeping 5 seconds), then it blocks until it gets the next value. And then it returns.
The only way to read a channel without blocking (that I know of) is to use a select statement with a default case.
go func() {
defer wg.Done()
for {
select {
case x, ok := <-c:
if ok && x == -1 {
fmt.Print(":")
return
}
default:
fmt.Print(".")
}
time.Sleep(time.Second)
}
}()
https://play.golang.org/p/nOG_hfih4D
I'm new to Go. When I comment out the second goroutine, there is a fatal error. I don't understand what causes this error to occur. Can you explain it to me?
package main
import (
"fmt"
"time"
)
func main() {
ch := make(chan int)
go func() {
for i := 0; i < 10; i++ {
ch <- i
}
} ()
// go func() {
for {
if num, ok := <-ch; !ok {
break
} else {
fmt.Printf("%d\n", num)
}
}
// } ()
time.Sleep(2 * time.Second)
close(ch)
}
This prints the following code:
0
1
2
3
4
5
6
7
8
9
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.main()
/tmp/sandbox169127128/main.go:17 +0xa0
Program exited.
The receiving for loop blocks on receive from ch after receiving all values from the sending goroutine. The runtime detects that the program is stuck and panics.
The fix is to close the channel after sending all values:
go func() {
for i := 0; i < 10; i++ {
ch <- i
}
close(ch)
} ()
Receive on the closed channel yields the value 0, false. The receiving for loop breaks on the false value.
Remove close(ch) from the end of the program.
Run it on the playground.
Because you're not closing the channel before the first goroutine exits. The below code should work.
package main
import (
"fmt"
"time"
)
func main() {
ch := make(chan int)
go func() {
for i := 0; i < 10; i++ {
ch <- i
}
close(ch)
} ()
//go func() {
for {
if num, ok := <-ch; !ok {
break
} else {
fmt.Printf("%d\n", num)
}
}
//} ()
time.Sleep(2 * time.Second)
}
Try it out here: https://play.golang.org/p/OdxNqbaZmj
Let's say I have an int channel in Go:
theint := make(chan int)
I want to wrap this channel in a new channel called incremented
incremented := make(chan int)
Such that:
go func() { theint <- 1 }
<- incremented // 2
appended can be assumed to be the only one that reads from the int.
It will work if a run a goroutine in the background
go func() {
for num := range theint {
incremented <- num + 1
}
}
However, I prefer to do it without a goroutine since I can't control it in my context.
Is there a simpler way to do it?
One thing that came to mind is python's yield:
for num in theint:
yield num + 1
Is something like this possible in go?
Generator pattern
What you are trying to implement is generator pattern. To use channels and goroutines for implementation of this pattern is totally common practice.
However, I prefer to do it without a goroutine since I can't control it in my context.
I believe the problem is deadlock
fatal error: all goroutines are asleep - deadlock!
To avoid deadlocks and orphaned (not closed) channels use sync.WaitGroup. This is an idiomatic way to control goroutines.
Playground
package main
import (
"fmt"
"sync"
)
func incGenerator(n []int) chan int {
ch := make(chan int)
var wg sync.WaitGroup
wg.Add(len(n))
for _, i := range n {
incremented := i + 1
go func() {
wg.Done()
ch <- incremented
}()
}
go func() {
wg.Wait()
close(ch)
}()
return ch
}
func main() {
n := []int{1, 2, 3, 4, 5}
for x := range incGenerator(n) {
fmt.Println(x)
}
}
One thing you can also consider is having a select on the int channel and an exit channel - in an infinite for loop. You can choose a variable increment value too. Please see code below:
package main
import (
"fmt"
"sync"
"time"
)
func main() {
var accum int //accumulator of incremented values
var wg sync.WaitGroup
c1 := make(chan int)
exChan := make(chan bool)
wg.Add(1)
go func() {
time.Sleep(time.Second * 1)
c1 <- 1
wg.Done()
}()
wg.Add(1)
go func() {
time.Sleep(time.Second * 2)
c1 <- 2
wg.Done()
}()
wg.Add(1)
go func() {
time.Sleep(time.Second * 2)
c1 <- 5
wg.Done()
}()
go func() {
wg.Wait()
close(exChan)
}()
for {
var done bool
select {
case incBy := <-c1: //Increment by value in channel
accum += incBy
fmt.Println("Received value to increment:", incBy, "; Accumulated value is", accum)
case d := <-exChan:
done = !(d)
}
if done == true {
break
}
}
fmt.Println("Final accumulated value is", accum)
}
Playground: https://play.golang.org/p/HmdRmMCN7U
Exit channel not needed, if we are having non-zero increments always. I like #I159 's approach too!
Anyways, hope this helps.
I'm new to the Go Language, and learning here:
https://tour.golang.org/concurrency/1
When I run https://play.golang.org/p/9JvbtSuv5o the result is:
world
hello
hello
So Added sync.WaitGroup: https://play.golang.org/p/vjdhnDssGk
package main
import (
"fmt"
"sync"
"time"
)
var w sync.WaitGroup
func say(s string) {
for i := 0; i < 2; i++ {
time.Sleep(100 * time.Millisecond)
fmt.Println(s)
}
w.Done()
}
func main() {
w.Add(1)
go say("world")
say("hello")
w.Wait()
}
But the result is same:
world
hello
hello
What is wrong with my code?
Please help,
Thank you for your help.
w.Done() decrements the WaitGroup counter.
So your code even sometimes panic: sync: negative WaitGroup counter.
You have two Goroutines:
1 - go say("world")
2 - say("hello") inside main Goroutine
so use w.Add(2), see this working sample (The Go Playground):
package main
import (
"fmt"
"sync"
"time"
)
var w sync.WaitGroup
func say(s string) {
for i := 0; i < 2; i++ {
time.Sleep(100 * time.Millisecond)
fmt.Println(s)
}
w.Done()
}
func main() {
w.Add(2)
go say("world")
say("hello")
w.Wait()
}
output:
world
hello
hello
world
I hope this helps.
You're only adding 1 to the WaitGroup, but calling Done from 2 invocations of say.
In your example, starting the WaitGroup with 2 would work
w.Add(2)
Problem occurs due to unconditional call to w.Done(). So when u called say("hello") this also decremented counter for waitGroup.
Refer https://play.golang.org/p/wJeAyYyjA2
package main
import (
"fmt"
"sync"
"time"
)
var w sync.WaitGroup
func say(s string, async bool) {
if async {
defer w.Done()
}
for i := 0; i < 2; i++ {
time.Sleep(100 * time.Millisecond)
fmt.Println(s)
}
}
func main() {
w.Add(1)
go say("world", true)
say("hello", false)
w.Wait()
}
I am learning Go and am working on this lesson from the GoTours. Here's what I have so far.
package main
import (
"fmt"
"code.google.com/p/go-tour/tree"
)
// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int) {
if t != nil {
Walk(t.Left, ch)
ch <- t.Value
Walk(t.Right, ch)
}
}
func main() {
var ch chan int = make(chan int)
go Walk(tree.New(1), ch)
for c := range ch {
fmt.Printf("%d ", c)
}
}
As you see, I try to test out my Walk function by printing out the values I wrote into a channel. However, I get the following error.
1 2 3 4 5 6 7 8 9 10 throw: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.main()
main.go:25 +0x85
goroutine 2 [syscall]:
created by runtime.main
/usr/local/go/src/pkg/runtime/proc.c:221
exit status 2
This error should be expected I think because I never close the channel. However, is there a way I could "catch" this deadlock error and deal with it programmatically?
Deadlock is similar to a nil pointer deference in that is represents a BUG in your program. This class of error is usually not recoverable for this reason.
As lbonn mentioned, the problem here is you need to "close(myChan)" your channel. If you do not do this the for-range loop, that the loop will wait for the next element forever.
You can try something like this:
func main() {
var ch chan int = make(chan int)
go func() {
Walk(tree.New(1), ch)
close(ch)
}()
for c := range ch {
fmt.Printf("%d ", c)
}
}
If you want to traverse the tree in parallel you will need to make further changes:
package main
import (
"code.google.com/p/go-tour/tree"
"fmt"
"sync"
)
// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int, done *sync.WaitGroup) {
if t != nil {
done.Add(2)
go Walk(t.Left, ch, done) //look at each branch in parallel
go Walk(t.Right, ch, done)
ch <- t.Value
}
done.Done()
}
func main() {
var ch chan int = make(chan int, 64) //note the buffer size
go func() {
done := new(sync.WaitGroup)
done.Add(1)
Walk(tree.New(1), ch, done)
done.Wait()
close(ch)
}()
for c := range ch {
fmt.Printf("%d ", c)
}
}
This deadlocks because, the range construct iterates until the channel is closed.
http://golang.org/ref/spec#For_statements
Here, you need to either close the channel when the tree is fully explored or use another construct.
For this example, you know that the trees are of size 10, so you can simply do a for loop from 1 to 10 and read from the channel once at each iteration.
No, you cannot recover from a deadlock.
The channel deadlock error is:
fatal error: all goroutines are asleep - deadlock!
channel deadlock is not a panic error, it's a fatal error, see https://golang.org/pkg/log/#Fatal
Fatal is equivalent to Print() followed by a call to os.Exit(1).
As you can see, Fatal will call os.Exit(1) at last, so it's totally different with panic, and that's why it can't be recover
I came up with this solution, It basically uses 2 channels and concludes the trees are same if both the channels are closed.
package main
import "golang.org/x/tour/tree"
import "fmt"
// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int) {
if t == nil {
return
}
Walk(t.Left, ch)
ch <- t.Value
Walk(t.Right, ch)
}
// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool {
tc1 := make(chan int)
tc2 := make(chan int)
go func() {
Walk(t1, tc1)
close(tc1)
}()
go func() {
Walk(t2, tc2)
close(tc2)
}()
for {
x1, y1 := <-tc1;
x2, y2 := <-tc2;
if x1 != x2 {
return false
}
if !y1 || !y2 {
return true
}
}
}
func main() {
t1, t2 := tree.New(123), tree.New(1)
fmt.Println(Same(t1, t2))
}
I'm following go-tour guide and only used resources taught so far (Unlike using sync package in the above solution.)