package main
import (
"fmt"
"runtime"
)
func main() {
runtime.GOMAXPROCS(1)
go spinner()
const n = 45
fibN := fib(n)
fmt.Printf("\rFibonacci(%d) = %d\n", n, fibN)
}
func spinner() {
for {
for _ = range `-\|/` {
}
}
}
func fib(x int) int {
fmt.Println(x)
if x < 2 {
return x
}
return fib(x-1) + fib(x-2)
}
After a few seconds, it stopped printing x
in fib
anymore. I deliberately use 1 processor to understand why it stops. Is the scheduler stuck and not rescheduling the goroutine running the fib
anymore?
Is the scheduler stuck and not rescheduling the goroutine running the fib anymore?
Short answer: yes.
Longer answer: you aren't guaranteed that this will happen, even with just one CPU. The system could do an occasional reschedule on its own. It's just that the implementation on which you are testing this, doesn't.
As JimB notes in a comment, the kind of hard-spin-loop you have in spinner
is ... unfriendly, at best. It should contain some method of releasing computing resources, such as spinning with time.After
or time.NewTicker
, or at the very least, call runtime.Gosched()
. I imagine your original spinner
was something like this, only without the time.NewTicker
:
func spinner() {
t := time.NewTicker(50 * time.Millisecond)
for {
for _, c := range `-\|/` {
fmt.Print(string(c), "\b")
<-t.C
}
}
}
With the ticker in place, the spinner spins pretty fast, but the program completes (despite the non-caching fib
). Of course a smarter fib
helps rather more:
var fibcache = map[int]int64{}
func fib(x int) int64 {
if x < 2 {
return int64(x)
}
r, ok := fibcache[x]
if !ok {
r = fib(x-1) + fib(x-2)
fibcache[x] = r
}
return r
}
(I changed the return type to int64
for what I hope are obvious reasons.) Now we can find Fibonacci(90) = 2880067194370816120
in 0.00 seconds (rounded).