好的,以下是如何在 Golang 中实现 HTTP Keep-Alive 和复用 http.Client
的示例。
1. 使用 HTTP Keep-Alive
在 Go 的 http.Client
中,默认情况下启用了 Keep-Alive。为了确保这一点并优化请求,我们可以创建一个自定义的 http.Transport
并将其传递给 http.Client
。下面的代码展示了如何做到这一点:
package main
import (
"fmt"
"io"
"net/http"
"os"
"sync"
)
var client = &http.Client{
Transport: &http.Transport{
MaxIdleConns: 100, // 最大空闲连接数
MaxIdleConnsPerHost: 10, // 每个主机最大空闲连接数
IdleConnTimeout: 90 * time.Second, // 空闲连接超时时间
},
}
func downloadFile(url string, wg *sync.WaitGroup) {
defer wg.Done()
resp, err := client.Get(url)
if err != nil {
fmt.Println("Error:", err)
return
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
fmt.Println("Server returned:", resp.Status)
return
}
out, err := os.Create("output_file") // 请根据实际需求修改文件名
if err != nil {
fmt.Println("Error creating file:", err)
return
}
defer out.Close()
if _, err = io.Copy(out, resp.Body); err != nil {
fmt.Println("Error downloading file:", err)
}
}
func main() {
urls := []string{
"http://example.com/file1",
"http://example.com/file2",
// 添加更多 URL
}
var wg sync.WaitGroup
for _, url := range urls {
wg.Add(1)
go downloadFile(url, &wg)
}
wg.Wait()
fmt.Println("All files downloaded.")
}
2. 控制并发数(使用 Buffered Channel)
在并发下载时,可以控制同一时间内并行执行的 goroutines 数量。这可以通过使用一个带缓冲区的 channel 来实现。例如:
package main
import (
"fmt"
"io"
"net/http"
"os"
"sync"
)
const maxConcurrentDownloads = 5
var client = &http.Client{
Transport: &http.Transport{
MaxIdleConns: 100,
MaxIdleConnsPerHost: 10,
IdleConnTimeout: 90 * time.Second,
},
}
func downloadFile(url string, wg *sync.WaitGroup) {
defer wg.Done()
resp, err := client.Get(url)
if err != nil {
fmt.Println("Error:", err)
return
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
fmt.Println("Server returned:", resp.Status)
return
}
out, err := os.Create("output_file") // 请根据实际需求修改文件名以避免覆盖文件。
if err != nil {
fmt.Println("Error creating file:", err)
return
}
defer out.Close()
if _, err = io.Copy(out, resp.Body); err != nil {
fmt.Println("Error downloading file:", err)
}
}
func main() {
urls := []string{
"http://example.com/file1",
"http://example.com/file2",
// 添加更多 URL...
}
var wg sync.WaitGroup
sem := make(chan struct{}, maxConcurrentDownloads) // 创建带缓冲的信道来限制并发数量
for _, url := range urls {
sem <- struct{}{} // 向信道发送一个值,占用一个位置,阻塞直到有空间可用。
wg.Add(1)
go func(u string) {
defer func() { <-sem }() // 完成后从信道中移除一个值,释放位置。
downloadFile(u, &wg)
}(url)
}
wg.Wait()
fmt.Println("All files downloaded.")
}
在这个示例中,我们通过创建一个带有 maxConcurrentDownloads
大小的通道来限制同时进行的下载操作。在每次启动新 goroutine 前,我们先向通道中发送一个空结构体,这样就占用了通道中的一个位置;而在完成下载后,再从通道中接收值,从而释放出该位置。
总结
以上两种方法结合起来可以有效地提高你的 Golang 程序在进行并发 HTTP 下载时的性能表现。你可以根据实际情况调整参数,比如最大并发下载数量等,以达到最佳效果。
内容由零声教学AI助手提供,问题来源于学员提问