为什么我的 goroutine 在几分钟 运行 后停止了?

Why my goroutine stopped after a few moments running?

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)
}

几秒钟后,它不再在 fib 中打印 x。我故意使用 1 个处理器来理解它停止的原因。调度程序是否卡住了并且不再重新调度 goroutine 运行 和 fib

Is the scheduler stuck and not rescheduling the goroutine running the fib anymore?

简答:是。

更长的答案:您无法保证这会发生,即使只有一个 CPU。系统可以偶尔自行重新安排时间。只是您正在测试它的实现没有。

一样,您在 spinner 中拥有的那种硬自旋循环是......充其量是不友好的。它应该包含一些释放计算资源的方法,例如用time.Aftertime.NewTicker旋转,或者至少调用runtime.Gosched()。我想你原来的 spinner 是这样的,只是没有 time.NewTicker:

func spinner() {
    t := time.NewTicker(50 * time.Millisecond)
    for {
        for _, c := range `-\|/` {
            fmt.Print(string(c), "\b")
            <-t.C
        }
    }
}

有了自动收报机,微调器旋转得非常快,但程序完成了(尽管没有缓存 fib)。当然,更聪明的 fib 帮助更多:

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
}

(出于明显的原因,我将 return 类型更改为 int64。)现在我们可以在 0.00 秒(四舍五入)内找到 Fibonacci(90) = 2880067194370816120