3

When an fmt.Print() line is removed from the code below, code runs infinitely. Why?

package main

import "fmt"
import "time"
import "sync/atomic"

func main() {
        var ops uint64 = 0 
        for i := 0; i < 50; i++ {
                go func() {
                        for {
                                atomic.AddUint64(&ops, 1)
                                fmt.Print()
                        }
                }()
        }
        time.Sleep(time.Second)
        opsFinal := atomic.LoadUint64(&ops)
        fmt.Println("ops:", opsFinal)
}
0

1 Answer 1

8

The Go By Example article includes:

   // Allow other goroutines to proceed.
   runtime.Gosched()

The fmt.Print() plays a similar role, and allows the main() to have a chance to proceed.

A export GOMAXPROCS=2 might help the program to finish even in the case of an infinite loop, as explained in "golang: goroute with select doesn't stop unless I added a fmt.Print()".

fmt.Print() explicitly passes control to some syscall stuff


Yes, go1.2+ has pre-emption in the scheduler

In prior releases, a goroutine that was looping forever could starve out other goroutines on the same thread, a serious problem when GOMAXPROCS provided only one user thread.

In Go 1.2, this is partially addressed: The scheduler is invoked occasionally upon entry to a function. This means that any loop that includes a (non-inlined) function call can be pre-empted, allowing other goroutines to run on the same thread.

Notice the emphasis (that I put): it is possible that in your example the for loop atomic.AddUint64(&ops, 1) is inlined. No pre-emption there.


Update 2017: Go 1.10 will get rid of GOMAXPROCS.

Sign up to request clarification or add additional context in comments.

4 Comments

This from golang.org: In prior releases, a goroutine that was looping forever could starve out other goroutines on the same thread, a serious problem when GOMAXPROCS provided only one user thread. In Go 1.2, this is partially addressed: The scheduler is invoked occasionally upon entry to a function. This means that any loop that includes a (non-inlined) function call can be pre-empted, allowing other goroutines to run on the same thread.
@xged it wouldn't work in playground though, as commented in stackoverflow.com/a/20836784/6309
@xged I have edited the answer: if the for loop is inlined, you won't have any pre-emption.
@xged probably because GOMAXPROCS is always 1 and, since it doesn't work outside playground (because of inlining), it wouldn't work inside playground.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.