Skip to main content
Returns the number of physical or logical CPU cores in the system.

Function Signatures

func Counts(logical bool) (int, error)
func CountsWithContext(ctx context.Context, logical bool) (int, error)

Parameters

logical
bool
required
If true, returns the number of logical CPUs (including hyperthreading). If false, returns the number of physical CPU cores.
ctx
context.Context
Context for cancellation and timeout control (WithContext variant only).

Return Value

int
int
The number of CPU cores. Returns the logical count if logical is true, physical count if false.
error
error
Error if the CPU count could not be determined, nil on success.

Examples

Get Logical and Physical Core Counts

package main

import (
    "fmt"
    "github.com/shirou/gopsutil/v4/cpu"
)

func main() {
    logical, err := cpu.Counts(true)
    if err != nil {
        panic(err)
    }
    
    physical, err := cpu.Counts(false)
    if err != nil {
        panic(err)
    }
    
    fmt.Printf("Logical CPUs: %d\n", logical)
    fmt.Printf("Physical CPUs: %d\n", physical)
    
    if logical > physical {
        fmt.Printf("Hyperthreading: enabled (%d threads per core)\n",
            logical/physical)
    } else {
        fmt.Println("Hyperthreading: disabled or not supported")
    }
}

Check CPU Resources

package main

import (
    "fmt"
    "runtime"
    "github.com/shirou/gopsutil/v4/cpu"
)

func main() {
    logical, _ := cpu.Counts(true)
    gomaxprocs := runtime.GOMAXPROCS(0)
    
    fmt.Printf("Available CPUs: %d\n", logical)
    fmt.Printf("GOMAXPROCS: %d\n", gomaxprocs)
    
    if gomaxprocs < logical {
        fmt.Println("Warning: Go is not using all available CPUs")
    }
}

Using Context with Timeout

package main

import (
    "context"
    "fmt"
    "time"
    "github.com/shirou/gopsutil/v4/cpu"
)

func main() {
    ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
    defer cancel()
    
    count, err := cpu.CountsWithContext(ctx, true)
    if err != nil {
        if ctx.Err() == context.DeadlineExceeded {
            fmt.Println("Operation timed out")
        } else {
            panic(err)
        }
        return
    }
    
    fmt.Printf("CPU count: %d\n", count)
}

Calculate Optimal Worker Pool Size

package main

import (
    "fmt"
    "github.com/shirou/gopsutil/v4/cpu"
)

func main() {
    logical, err := cpu.Counts(true)
    if err != nil {
        panic(err)
    }
    
    // Common pattern: use 2x CPU count for I/O-bound tasks
    ioWorkers := logical * 2
    fmt.Printf("Recommended I/O workers: %d\n", ioWorkers)
    
    // Use CPU count for CPU-bound tasks
    cpuWorkers := logical
    fmt.Printf("Recommended CPU workers: %d\n", cpuWorkers)
}

Compare with runtime.NumCPU

package main

import (
    "fmt"
    "runtime"
    "github.com/shirou/gopsutil/v4/cpu"
)

func main() {
    gopsutilCount, _ := cpu.Counts(true)
    runtimeCount := runtime.NumCPU()
    
    fmt.Printf("gopsutil logical CPUs: %d\n", gopsutilCount)
    fmt.Printf("runtime.NumCPU(): %d\n", runtimeCount)
    
    // These should typically be the same
    if gopsutilCount == runtimeCount {
        fmt.Println("Counts match")
    } else {
        fmt.Println("Warning: Counts differ")
    }
}

System Information Summary

package main

import (
    "fmt"
    "github.com/shirou/gopsutil/v4/cpu"
)

func main() {
    logical, err := cpu.Counts(true)
    if err != nil {
        panic(err)
    }
    
    physical, err := cpu.Counts(false)
    if err != nil {
        panic(err)
    }
    
    info, err := cpu.Info()
    if err != nil {
        panic(err)
    }
    
    fmt.Println("=== CPU Information ===")
    if len(info) > 0 {
        fmt.Printf("Model: %s\n", info[0].ModelName)
        fmt.Printf("Vendor: %s\n", info[0].VendorID)
    }
    fmt.Printf("Physical Cores: %d\n", physical)
    fmt.Printf("Logical Cores: %d\n", logical)
    fmt.Printf("Threads per Core: %d\n", logical/physical)
}

Notes

  • The Counts() function is a convenience wrapper that calls CountsWithContext() with context.Background()
  • Logical count includes hyperthreading/SMT threads
    • On Intel CPUs with hyperthreading: logical = physical × 2
    • On AMD CPUs with SMT: logical = physical × 2
    • On CPUs without hyperthreading: logical = physical
  • The logical count is equivalent to runtime.NumCPU() in Go
  • Physical count represents actual CPU cores, not including hyperthreading
  • On some platforms (Plan 9, older systems), both logical and physical may return the same value
  • This is useful for determining optimal parallelism for CPU-bound tasks

Build docs developers (and LLMs) love