调度策略优化
- 减少系统调用:
- 尽量避免在Goroutine中频繁进行系统调用,因为系统调用会导致上下文切换,可能影响性能。例如,在处理网络请求时,如果需要读取文件,尽量批量读取,而不是每次请求都进行文件读取系统调用。
- 示例代码:
// 假设这是处理请求的函数,原本每次请求都读取文件
func handleRequest1() {
data, err := ioutil.ReadFile("config.txt")
if err != nil {
// 处理错误
}
// 处理数据
}
// 优化后,提前读取文件,避免每次请求都进行系统调用
var configData []byte
func init() {
var err error
configData, err = ioutil.ReadFile("config.txt")
if err != nil {
// 处理错误
}
}
func handleRequest2() {
// 使用已读取的configData处理请求
}
- GOMAXPROCS设置:
GOMAXPROCS
决定了同时可以执行的最大CPU数。合理设置该值可以充分利用多核CPU的性能。如果设置过小,可能无法充分利用CPU资源;设置过大,可能会导致过多的上下文切换。
- 示例代码:
func main() {
// 获取CPU核心数,并设置GOMAXPROCS
numCPU := runtime.NumCPU()
runtime.GOMAXPROCS(numCPU)
// 启动网络服务等操作
}
- 调度器调优:
- Go的调度器是M:N调度模型(M个Goroutine映射到N个操作系统线程)。可以通过了解调度器的原理,优化Goroutine的创建和执行。例如,避免在一个Goroutine中长时间阻塞,因为这可能会导致其他Goroutine得不到执行机会。
- 示例代码:
// 假设这是一个可能长时间阻塞的函数
func longRunningTask() {
// 模拟长时间运行
time.Sleep(10 * time.Second)
}
// 优化方式,将长时间运行的任务放到单独的Goroutine中,并通过通道获取结果
func optimizedLongRunningTask() {
resultCh := make(chan int)
go func() {
// 模拟长时间运行并计算结果
time.Sleep(10 * time.Second)
result := 42
resultCh <- result
close(resultCh)
}()
// 可以在主线程中做其他事情,然后获取结果
result := <-resultCh
}
资源分配优化
- 内存管理:
- 避免频繁的内存分配和释放。例如,使用对象池来复用对象,减少垃圾回收(GC)的压力。
- 示例代码:
package main
import (
"fmt"
"sync"
)
type MyObject struct {
// 定义对象的字段
Data int
}
var objectPool = sync.Pool{
New: func() interface{} {
return &MyObject{}
},
}
func main() {
obj := objectPool.Get().(*MyObject)
// 使用obj
obj.Data = 10
fmt.Println(obj.Data)
objectPool.Put(obj)
}
- 网络资源:
- 优化网络连接的复用。对于HTTP服务,可以使用HTTP/2,它支持多路复用,减少连接开销。同时,合理设置连接池的大小,避免过多或过少的连接。
- 示例代码(使用Go标准库的HTTP连接池):
package main
import (
"fmt"
"net/http"
"time"
)
func main() {
transport := &http.Transport{
MaxIdleConns: 10,
IdleConnTimeout: 30 * time.Second,
DisableCompression: false,
}
client := &http.Client{Transport: transport}
resp, err := client.Get("http://example.com")
if err != nil {
// 处理错误
}
defer resp.Body.Close()
// 处理响应
}
- 数据库资源:
- 如果服务需要与数据库交互,合理设置数据库连接池。避免每个请求都创建新的数据库连接,减少数据库连接建立和关闭的开销。
- 示例代码(使用
database/sql
包的连接池):
package main
import (
"database/sql"
"fmt"
_ "github.com/go - sql - driver/mysql"
)
func main() {
db, err := sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/test")
if err != nil {
// 处理错误
}
defer db.Close()
// 设置最大空闲连接数
db.SetMaxIdleConns(10)
// 设置最大打开连接数
db.SetMaxOpenConns(100)
rows, err := db.Query("SELECT * FROM users")
if err != nil {
// 处理错误
}
defer rows.Close()
// 处理查询结果
}
其他优化
- 代码逻辑优化:
- 简化业务逻辑,去除不必要的计算和条件判断。例如,在请求处理函数中,避免重复计算已经计算过的结果。
- 示例代码:
// 原本每次都计算相同结果的函数
func handleRequest3() {
result := complexCalculation()
// 处理结果
result = complexCalculation()
// 再次处理结果
}
// 优化后,只计算一次
func handleRequest4() {
result := complexCalculation()
// 多次处理结果
}
func complexCalculation() int {
// 模拟复杂计算
var sum int
for i := 0; i < 1000000; i++ {
sum += i
}
return sum
}
- 同步机制优化:
- 减少锁的使用范围和时间。如果多个Goroutine需要访问共享资源,尽量使用无锁数据结构或者读写锁(
sync.RWMutex
)来提高并发性能。
- 示例代码(使用读写锁):
package main
import (
"fmt"
"sync"
)
var (
data = make(map[string]int)
rwMutex sync.RWMutex
)
func read(key string) int {
rwMutex.RLock()
value := data[key]
rwMutex.RUnlock()
return value
}
func write(key string, value int) {
rwMutex.Lock()
data[key] = value
rwMutex.Unlock()
}