协程池管理
- 使用有界协程池:避免创建过多协程导致资源耗尽。可以通过
channel
来实现简单的协程池。
package main
import (
"fmt"
"sync"
)
func worker(id int, jobs <-chan int, wg *sync.WaitGroup) {
defer wg.Done()
for j := range jobs {
fmt.Printf("Worker %d started job %d\n", id, j)
// 模拟网页抓取任务
fmt.Printf("Worker %d finished job %d\n", id, j)
}
}
func main() {
const numJobs = 10
jobs := make(chan int, numJobs)
var wg sync.WaitGroup
// 初始化协程池,例如5个协程
const numWorkers = 5
for w := 1; w <= numWorkers; w++ {
wg.Add(1)
go worker(w, jobs, &wg)
}
// 提交任务
for j := 1; j <= numJobs; j++ {
jobs <- j
}
close(jobs)
wg.Wait()
}
- 关键优化点:
- 合理设置协程池大小,根据系统资源(CPU、内存、网络带宽等)进行调整。
- 任务分配要均衡,避免某个协程负载过重。
网络I/O优化
- 使用连接池:复用TCP连接,减少连接建立和关闭的开销。可以使用
net/http
包中的Transport
来设置连接池。
package main
import (
"fmt"
"net/http"
"sync"
)
func fetch(url string, client *http.Client, wg *sync.WaitGroup) {
defer wg.Done()
resp, err := client.Get(url)
if err != nil {
fmt.Printf("Error fetching %s: %v\n", url, err)
return
}
defer resp.Body.Close()
// 处理响应
fmt.Printf("Fetched %s successfully\n", url)
}
func main() {
urls := []string{
"http://example.com",
"http://example.org",
}
var wg sync.WaitGroup
transport := &http.Transport{
MaxIdleConns: 10,
IdleConnTimeout: 30 * time.Second,
}
client := &http.Client{Transport: transport}
for _, url := range urls {
wg.Add(1)
go fetch(url, client, &wg)
}
wg.Wait()
}
- 优化请求头:精简不必要的请求头,减少数据传输量。
- 异步I/O:Go语言的
net/http
包默认是异步的,但在处理响应时,可以进一步优化,例如使用io.Copy
的异步版本io.CopyBuffer
,并合理设置缓冲区大小。
内存管理
- 对象复用:避免频繁创建和销毁大对象。例如,在处理网页响应时,可以复用缓冲区。
package main
import (
"bytes"
"fmt"
"io"
"net/http"
)
func fetch(url string) {
resp, err := http.Get(url)
if err != nil {
fmt.Printf("Error fetching %s: %v\n", url, err)
return
}
defer resp.Body.Close()
var buf bytes.Buffer
io.Copy(&buf, resp.Body)
// 处理buf中的数据
fmt.Printf("Fetched data from %s: %s\n", url, buf.String())
}
- 及时释放资源:在使用完资源(如文件句柄、网络连接等)后,及时关闭。在Go语言中,使用
defer
关键字来确保资源在函数结束时被正确释放。
- 垃圾回收优化:尽量减少内存碎片,避免短生命周期对象的频繁创建和销毁。可以使用对象池(如
sync.Pool
)来复用对象。
package main
import (
"fmt"
"sync"
)
var bufferPool = sync.Pool{
New: func() interface{} {
return &bytes.Buffer{}
},
}
func processData() {
buf := bufferPool.Get().(*bytes.Buffer)
defer bufferPool.Put(buf)
buf.Reset()
// 使用buf处理数据
fmt.Println("Using buffer from pool")
}