Search code examples
gogoroutine

What are the three background goroutines in a Go program?


Go seems to always have at least 4 goroutines running at any given time. What are the other three that are not the main goroutine?

http://play.golang.org/p/MQBiLmHXBK

package main

import (
    "fmt"
    "runtime"
)

func main() {
    fmt.Println(runtime.NumGoroutine()) //4
}

Solution

  • Those aren't threads, they're goroutines, and the number may vary based on current implementation (i.e. in go1.2 it would have printed 2).

    Right now, it looks like you have 1 for main, and 3 for runtime/gc.

    import "fmt"
    
    func main() {
        fmt.Println(func() string { panic(nil); return "" }())
    }
    

    This shows

    goroutine 16 [running]:
    runtime.panic(0x0, 0x0)
        /usr/local/go/src/pkg/runtime/panic.c:279 +0xf5
    main.func·001(0x3ea4f, 0xdc4b0)
        /test/threads.go:6 +0x28
    main.main()
        /test/threads.go:6 +0x1e
    
    goroutine 17 [runnable]:
    runtime.MHeap_Scavenger()
        /usr/local/go/src/pkg/runtime/mheap.c:507
    runtime.goexit()
        /usr/local/go/src/pkg/runtime/proc.c:1445
    
    goroutine 18 [runnable]:
    bgsweep()
        /usr/local/go/src/pkg/runtime/mgc0.c:1976
    runtime.goexit()
        /usr/local/go/src/pkg/runtime/proc.c:1445
    
    goroutine 19 [runnable]:
    runfinq()
        /usr/local/go/src/pkg/runtime/mgc0.c:2606
    runtime.goexit()
        /usr/local/go/src/pkg/runtime/proc.c:1445
    

    if you remove fmt, and use the bootstrapping print function you only get 2 goroutines.

    import "runtime"
    
    func main() {
        print(runtime.NumGoroutine(), "\n")
    }
    
    // prints 2
    

    If you ever want to know exactly what goroutines are running, print a stack trace, call panic, or kill the process with SIGQUIT (which prints a stack trace and exits). If you run the absolute minimum program you can get a stack trace from you can see the 2 goroutines:

    package main
    
    func main() {
        panic(nil)
    }
    

    Goroutines are very inexpensive, and many things will start and stop more goroutines, so trying to track their lower bound isn't very useful. Notice how even though there's only 2 goroutines, (main/runtime.panic, and runtime.MHeap_Scavenger), the count is already up to 17.

    panic: nil
    
    goroutine 16 [running]:
    runtime.panic(0x0, 0x0)
        /usr/local/go/src/pkg/runtime/panic.c:279 +0xf5
    main.main()
        /test/threads.go:4 +0x28
    
    goroutine 17 [runnable]:
    runtime.MHeap_Scavenger()
        /usr/local/go/src/pkg/runtime/mheap.c:507
    runtime.goexit()
        /usr/local/go/src/pkg/runtime/proc.c:1445
    exit status 2