优化思路
- CPU密集型任务:
- 由于CPU密集型任务长时间占用CPU资源,应尽量避免过多此类任务同时运行,以免导致CPU资源竞争激烈。可以根据CPU核心数,合理限制并发执行的CPU密集型Goroutine数量。
- 优先将CPU资源分配给这些任务,因为它们对CPU计算能力要求高。
- I/O密集型任务:
- I/O密集型任务在等待I/O操作完成时会让出CPU,所以可以让更多的I/O密集型Goroutine并发运行。
- 利用I/O操作等待时间,调度器可以切换到其他可运行的任务,包括CPU密集型任务,提高CPU利用率。
实现方法
- 限制CPU密集型任务并发数:
- 使用
sync.WaitGroup
和channel
来控制并发数。例如:
package main
import (
"fmt"
"sync"
)
func cpuIntensiveTask(id int, wg *sync.WaitGroup, sem chan struct{}) {
defer wg.Done()
sem <- struct{}{}
defer func() { <-sem }()
// 模拟CPU密集型计算
for i := 0; i < 1000000000; i++ {
_ = i * i
}
fmt.Printf("CPU intensive task %d finished\n", id)
}
func main() {
var wg sync.WaitGroup
maxCPUConcurrency := 4
sem := make(chan struct{}, maxCPUConcurrency)
for i := 0; i < 10; i++ {
wg.Add(1)
go cpuIntensiveTask(i, &wg, sem)
}
wg.Wait()
}
- 在上述代码中,
sem
是一个带缓冲的通道,其缓冲大小为maxCPUConcurrency
,控制同时运行的CPU密集型任务数量。
- I/O密集型任务调度:
- Go语言的调度器默认对I/O密集型任务有较好的支持。当I/O操作阻塞时,调度器会自动切换到其他可运行的Goroutine。
- 例如对于网络I/O操作,可以使用标准库的
net/http
包等进行操作:
package main
import (
"fmt"
"io/ioutil"
"net/http"
"sync"
)
func ioIntensiveTask(url string, wg *sync.WaitGroup) {
defer wg.Done()
resp, err := http.Get(url)
if err != nil {
fmt.Printf("Error fetching %s: %v\n", url, err)
return
}
defer resp.Body.Close()
_, err = ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Printf("Error reading %s: %v\n", url, err)
return
}
fmt.Printf("I/O intensive task for %s finished\n", url)
}
func main() {
var wg sync.WaitGroup
urls := []string{
"http://example.com",
"http://google.com",
// 更多URL
}
for _, url := range urls {
wg.Add(1)
go ioIntensiveTask(url, &wg)
}
wg.Wait()
}
- 这里多个I/O密集型任务(HTTP请求)可以并发执行,在等待响应时调度器会调度其他Goroutine运行。
- 全局调度优化:
- 可以使用
runtime.GOMAXPROCS
函数设置Go程序能使用的CPU核心数,以匹配硬件资源,充分利用多核CPU性能。例如:
package main
import (
"fmt"
"runtime"
)
func main() {
numCPU := runtime.NumCPU()
runtime.GOMAXPROCS(numCPU)
fmt.Printf("Using %d CPU cores\n", numCPU)
// 启动任务等操作
}
- 这样可以让CPU密集型任务更好地并行执行,同时配合I/O密集型任务的调度,提高整体系统性能。