# 查看 CPU 使用率
top
htop
# 查看 CPU 详细信息
mpstat -P ALL 1
# 查看进程 CPU 使用
ps aux --sort=-%cpu | head -10CPU 瓶颈特征:
- CPU 使用率持续 > 80%
- 用户态 CPU (us) 占比高
- 负载 (load average) 持续 > CPU 核心数
核心原则:降低时间复杂度
// ❌ O(n²) 暴力查找
func findDuplicatesSlow(nums []int) []int {
var result []int
for i := 0; i < len(nums); i++ {
for j := i + 1; j < len(nums); j++ {
if nums[i] == nums[j] {
result = append(result, nums[i])
break
}
}
}
return result
}
// ✅ O(n) 哈希表优化
func findDuplicatesFast(nums []int) []int {
seen := make(map[int]bool)
var result []int
for _, num := range nums {
if seen[num] {
result = append(result, num)
}
seen[num] = true
}
return result
}性能对比:
- 输入 10000 个元素
- O(n²) 版本:~500ms
- O(n) 版本:~5ms
- 性能提升:100x
import "container/list"
// ✅ 高效 LRU:哈希表 + 双向链表,O(1) 读写
type LRUCache struct {
capacity int
cache map[int]*list.Element
lruList *list.List
}
type entry struct {
key int
value int
}
func NewLRUCache(capacity int) *LRUCache {
return &LRUCache{
capacity: capacity,
cache: make(map[int]*list.Element),
lruList: list.New(),
}
}
func (c *LRUCache) Get(key int) int {
if elem, ok := c.cache[key]; ok {
c.lruList.MoveToFront(elem) // O(1)
return elem.Value.(*entry).value
}
return -1
}
func (c *LRUCache) Put(key, value int) {
if elem, ok := c.cache[key]; ok {
c.lruList.MoveToFront(elem)
elem.Value.(*entry).value = value
return
}
if c.lruList.Len() == c.capacity {
back := c.lruList.Back()
if back != nil {
c.lruList.Remove(back)
delete(c.cache, back.Value.(*entry).key)
}
}
elem := c.lruList.PushFront(&entry{key, value})
c.cache[key] = elem
}性能对比:
- 数组实现(每次查找 O(n)):1000 ops/s
- 哈希表+链表(O(1)):100000 ops/s
- 性能提升:100x
import (
"sync"
"runtime"
)
// ❌ 串行处理
func processDataSerial(data []int) []int {
result := make([]int, len(data))
for i, v := range data {
result[i] = expensiveCompute(v) // 耗时操作
}
return result
}
// ✅ 并行处理
func processDataParallel(data []int) []int {
result := make([]int, len(data))
numWorkers := runtime.NumCPU()
chunkSize := (len(data) + numWorkers - 1) / numWorkers
var wg sync.WaitGroup
for i := 0; i < numWorkers; i++ {
wg.Add(1)
go func(workerID int) {
defer wg.Done()
start := workerID * chunkSize
end := start + chunkSize
if end > len(data) {
end = len(data)
}
for j := start; j < end; j++ {
result[j] = expensiveCompute(data[j])
}
}(i)
}
wg.Wait()
return result
}性能对比(8核CPU):
- 串行:800ms
- 并行:120ms
- 性能提升:6.7x
// ❌ 缓存不友好:按列遍历
func sumColumnsBad(matrix [][]int) int {
sum := 0
rows := len(matrix)
cols := len(matrix[0])
for col := 0; col < cols; col++ {
for row := 0; row < rows; row++ {
sum += matrix[row][col] // 缓存未命中
}
}
return sum
}
// ✅ 缓存友好:按行遍历
func sumColumnsGood(matrix [][]int) int {
sum := 0
for _, row := range matrix {
for _, val := range row { // 顺序访问,缓存命中
sum += val
}
}
return sum
}性能对比(1000x1000 矩阵):
- 按列遍历:45ms(缓存未命中率高)
- 按行遍历:15ms(缓存命中率高)
- 性能提升:3x
// ❌ 频繁函数调用
func calculateSlow(data []int) int {
sum := 0
for _, v := range data {
sum += square(v) // 函数调用开销
}
return sum
}
func square(x int) int {
return x * x
}
// ✅ 内联计算
func calculateFast(data []int) int {
sum := 0
for _, v := range data {
sum += v * v // 直接计算,无调用开销
}
return sum
}Go 编译器优化提示:
// 使用 //go:inline 提示编译器内联
//go:inline
func square(x int) int {
return x * x
}
// 或使用 -gcflags="-m" 查看内联决策
// go build -gcflags="-m" main.goimport "sync"
// ✅ 使用 sync.Once 避免重复计算
type Config struct {
once sync.Once
result *ExpensiveResult
}
func (c *Config) GetResult() *ExpensiveResult {
c.once.Do(func() {
c.result = expensiveComputation() // 只计算一次
})
return c.result
}
// ✅ 使用记忆化(Memoization)
type Fibonacci struct {
cache map[int]int
mu sync.RWMutex
}
func (f *Fibonacci) Compute(n int) int {
// 先读缓存
f.mu.RLock()
if val, ok := f.cache[n]; ok {
f.mu.RUnlock()
return val
}
f.mu.RUnlock()
// 计算并缓存
f.mu.Lock()
defer f.mu.Unlock()
// Double-check
if val, ok := f.cache[n]; ok {
return val
}
if n <= 1 {
f.cache[n] = n
return n
}
result := f.Compute(n-1) + f.Compute(n-2)
f.cache[n] = result
return result
}- 减少 CPU 缓存失效
- 减少上下文切换
- 提升多核性能
# 绑定进程到 CPU 0-3
taskset -c 0-3 ./my_app
# 绑定运行中的进程
taskset -cp 0-3 <pid>
# 查看进程的 CPU 亲和性
taskset -cp <pid>import (
"runtime"
"syscall"
)
// 设置 Goroutine 到特定 CPU
func setGoroutineAffinity(cpuID int) {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
var cpuSet syscall.CPUSet
cpuSet.Set(cpuID)
err := syscall.SchedSetaffinity(0, &cpuSet)
if err != nil {
panic(err)
}
}
// 使用示例
func worker(cpuID int) {
setGoroutineAffinity(cpuID)
// 密集计算任务
for {
// ...
}
}
func main() {
numCPU := runtime.NumCPU()
for i := 0; i < numCPU; i++ {
go worker(i)
}
select {}
}使用 Go 汇编实现 SIMD:
// sum_amd64.s
TEXT ·SumSIMD(SB), NOSPLIT, $0-24
MOVQ arr+0(FP), SI
MOVQ len+8(FP), CX
XORPS X0, X0 // 清零 XMM0
loop:
MOVUPS (SI), X1 // 加载 4 个 float32
ADDPS X1, X0 // SIMD 加法
ADDQ $16, SI
SUBQ $4, CX
JA loop
// 水平求和 XMM0
MOVHLPS X0, X1
ADDPS X1, X0
MOVAPS X0, X1
SHUFPS $1, X1, X1
ADDSS X1, X0
MOVSS X0, ret+16(FP)
RET性能对比:
- 普通循环:100ms
- SIMD 优化:25ms
- 性能提升:4x
// ❌ 分支预测失败
func processBad(data []int) int {
sum := 0
for _, v := range data {
if v % 2 == 0 { // 随机分支,预测失败率高
sum += v
}
}
return sum
}
// ✅ 减少分支
func processGood(data []int) int {
sum := 0
for _, v := range data {
sum += v * (v % 2) // 无分支,用算术代替
}
return sum
}# 记录 CPU profile
perf record -g ./my_app
# 查看报告
perf report
# 实时查看热点
perf top
# 查看缓存未命中
perf stat -e cache-misses,cache-references ./my_appimport (
"net/http"
_ "net/http/pprof"
)
func main() {
// 启用 pprof
go http.ListenAndServe("localhost:6060", nil)
// 业务代码
// ...
}使用方式:
# 采集 30 秒 CPU profile
go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30
# 生成火焰图
go tool pprof -http=:8080 cpu.prof
# 查看 top 函数
go tool pprof -top cpu.prof# 使用 perf 生成火焰图
perf record -F 99 -g ./my_app
perf script > out.perf
stackcollapse-perf.pl out.perf > out.folded
flamegraph.pl out.folded > flame.svg火焰图解读:
- X 轴:按字母排序(非时间)
- Y 轴:调用栈深度
- 宽度:占用 CPU 时间
- 颜色:区分不同函数
场景:某 API 需要返回大量 JSON 数据,CPU 占用高
优化步骤:
go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30
# 发现 encoding/json.Marshal 占用 80% CPUimport (
"encoding/json"
jsoniter "github.com/json-iterator/go"
)
// ❌ 标准库 JSON
func serializeStd(data interface{}) []byte {
bytes, _ := json.Marshal(data)
return bytes
}
// ✅ 高性能 JSON 库
var json = jsoniter.ConfigCompatibleWithStandardLibrary
func serializeFast(data interface{}) []byte {
bytes, _ := json.Marshal(data)
return bytes
}# Benchmark 对比
BenchmarkStdJSON-8 1000 1200000 ns/op
BenchmarkFastJSON-8 5000 250000 ns/op性能提升:4.8x
import (
"strings"
"bytes"
)
// ❌ 低效:每次拼接都创建新字符串
func concatSlow(strs []string) string {
result := ""
for _, s := range strs {
result += s // O(n²) 复杂度
}
return result
}
// ✅ 高效:使用 strings.Builder
func concatFast(strs []string) string {
var builder strings.Builder
builder.Grow(estimateSize(strs)) // 预分配容量
for _, s := range strs {
builder.WriteString(s) // O(n) 复杂度
}
return builder.String()
}
func estimateSize(strs []string) int {
size := 0
for _, s := range strs {
size += len(s)
}
return size
}Benchmark 对比:
BenchmarkConcatSlow-8 1000 1500000 ns/op 500000 B/op 1000 allocs/op
BenchmarkConcatFast-8 50000 25000 ns/op 8192 B/op 1 allocs/op
性能提升:60x
- 时间复杂度是否最优?(O(n²) → O(n log n) → O(n))
- 是否使用了合适的数据结构?(哈希表、堆、树)
- 是否避免了重复计算?(缓存、记忆化)
- 是否充分利用多核?(并行处理)
- 是否减少了锁竞争?(细粒度锁、无锁数据结构)
- 是否使用了 Goroutine Pool?(避免频繁创建)
- 是否减少了函数调用?(内联)
- 是否优化了循环?(循环展开、向量化)
- 是否利用了 CPU 缓存?(数据局部性)
- 是否减少了分支?(分支预测)
- 是否绑定了 CPU 亲和性?
- 是否调优了 GOMAXPROCS?
- 是否使用了编译器优化?(-O2、-O3)
核心要点:
- ✅ 算法优先:时间复杂度的优化收益最大
- ✅ 并发利用:充分利用多核 CPU
- ✅ 缓存友好:优化数据访问模式,提升缓存命中率
- ✅ 减少开销:减少函数调用、内存分配
- ✅ 工具分析:使用 perf、pprof、火焰图定位瓶颈
优化优先级:
算法优化 > 并发优化 > 缓存优化 > 代码细节优化