goroutine is not be scheduled again

716 views Asked by At

I'm learning golang. I have a goroutine to print variable i and after it I write a deadloop. But when var i up to 491519(or some other value), there is no output on the terminal. It looks like the goroutine which print var i is no longer be scheduled, the CPU execute the deadloop all the way after output 491519. Who can tell me the reason?
thanks.

My code:

package main

import (
    "fmt"
    "runtime"
)

func main() {
        go func() {
                i := 1
                for {
                        fmt.Println(i)
                        i = i + 1
                }
        }()
        runtime.GOMAXPROCS(4)
        for {
        }
}

I'd like to add that:
When I add fmt.Println("ABC") in the last deadloop, the alternation of ABC or i output on the terminal forever.

my go version: go version go1.9.1 darwin/amd64

2

There are 2 answers

1
Grzegorz Żur On BEST ANSWER

Goroutines are scheduled by Go runtime, therefore there are some limitations in comparison to the processes scheduling done by an operating system. An operating system can preempt processes by using timed interrupts, Go runtime cannot preempt goroutines.

Go runtime schedules another goroutine when goroutine

  • makes channel operation (this includes select statement, even empty)
  • make system call
  • explicitly calls runtime.Gosched

Setting GOMAXPROCS does not help much. Take a look at following program. It will use all processors and will stay in tight busy loops.

func runForever() {
   for {
   }
}

func main() {
    for i := 0; i < runtime.GOMAXPROCS(-1); i++ {
        go runForever()
    }
    time.Sleep(time.Second)
}

There are few ways of fixing your program:

go func() {
    for i:= 1; true; i++ {
        fmt.Println(i)
    }
}()

for {
    runtime.Gosched()
}

Or

go func() {
    for i:= 1; true; i++ {
        fmt.Println(i)
    }
}()

select {
}

The work on improving the case of tight loops is ongoing.

4
Adrian On

The dead loop will use a ton of CPU and possibly cause scheduler issues. If you want to block a goroutine, it's much more efficient to read from a channel that's never written:

ch := make(chan struct{})
<-ch

Or better still, set up a channel to wait for a signal to close the application:

stop := make(chan os.Signal, 1)
signal.Notify(stop, os.Interrupt)
<-stop

Also there should be no need to set GOMAXPROCS.