ZBLOG

以上第二点和第三点如何实现

好的,以下是如何在 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助手提供,问题来源于学员提问

本站部分文章来源于网络,版权归原作者所有,如有侵权请联系站长删除。
转载请注明出处:https://golang.0voice.com/?id=18951

分享:
扫描分享到社交APP
上一篇
下一篇
发表列表
游客 游客
此处应有掌声~
评论列表

还没有评论,快来说点什么吧~

联系我们

在线咨询: 点击这里给我发消息

微信号:3007537140

上班时间: 10:30-22:30

关注我们
x

注册

已经有帐号?