开发者

Go语言实现多协程并发下载网页内容的完整代码

目录
  • 一、实战背景
  • 二、实战目标
  • 三、完整代码实现
  • 四、输出示例
  • 五、重点知识点讲解
    • 1. 使用 Goroutine 启动并发请求
    • 2. 使用 sync.WaitGroup 等待所有任务完成
    • 3. 使用带缓冲的 Channel 收集结果
    • 4. 设置请求超时
    • 5. 防止通道未关闭阻塞
  • 六、可扩展方向
    • 七、小结

      一、实战背景

      在互联网项目中,我们常需要批量获取多个网页的内容,例如:

      • 爬虫程序抓取网页 html
      • 数据聚合服务请求多个 API
      • 批量检测多个 URL 的可用性

      如果逐个请求(串行),效率将非常低下。Go 天生支持高并发,我们可以用 Goroutine 实现 多协程并发下载网页内容,显著提高吞吐能力。

      二、实战目标

      我们将构建一个小型并发网页下载器,具备以下能力:

      1. 输入一组网址列表
      2. 使用 Goroutine 并发请求多个网页
      3. 使用 Channel 收集下载结果
      4. 打印成功/失败状态与网页内容摘要
      5. 支持 WaitGroup 等待所有任务完成

      三、完整代码实现

      package main
      
      import (
          "fmt"
          "io"
          "net/http"
          "strings"
          "sync"
          "time"
      )
      
      type Result struct {
          URL    string
          Status string
          Length int
          Error  error
      }
      
      // 下载网页内容并写入结果通道
      func fetchURL(url string, wg *sync.WaitGroup, resultCh chan<- Result) {
          defer wg.Done()
      
          client := http.Client{
              Timeout: 5 * time.Second,
          }
      
          resp, err := client.Get(url)
          if err != nil {
              resultCh <- Result{URL: url, Status: "请求失败", Error: err}
              return
          }
          defer resp.Body.Close()
      
          body, err := io.ReadAll(resp.Body)
          if err != nil {
              resultCh <- Result{URL: url, Status: "读取失败", Error: err}
              return
          }
      
          resultCh <- Result{
              URL:    url,
              Status: resp.Status,
              Length: len(body),
          }
      }
      
      func main() {
          urls := []string{
              "https://example.com",
              "https://httpbin.org/get",
              "https://golang.org",
              "https://nonexistent.example.com", // 故意的错误URL
          }
      
          var wg sync.WaitGroup
          resultCh := make(chan Result,javascript len(urls))
      
          // 启动多个下载协程
          for _, url := raandroidnge urls {
          编程客栈    wg.Add(1)
              go fetchURL(url, &wg, resultCh)
          }
      
          // 等待所有任务完成后关闭通道
          go func() {
              wg.Wait()
              close(resultCh)
          }()
      
          // 读取结果
          for res := range resultCh {
              if res.Error != nil {
                  fmt.Printf("[失败] %s:%v\n", res.URL, res.Error)
              } else {
                  snippet := fmt.Sprintf("%d 字节", res.Length)
                  if res.Length > 0 {
                      snippet = fmt.Sprintf("%s 内容预览:%s", snippet, strings.TrimSpace(string([]byte(res.URL)[:min(50, res.Length)])))
                  }
                  fmt.Printf("[成功] %s:%s\n", res.URL, snippet)
              }
          }
      
          fmt.Println("所有网页请求已完成。")
      }
      
      func min(a, b int) int {
          if a < b {
              return a
          }
          return b
      }
      

      四、输出示例

      [成功] https://example.com:1256 字节 内容预览:https://example.com
      [成功] https://httpbin.org/get:349 字节 内容预览:https://httpbin.org/get
      [成功] https://golang.org:3578 字节 内容预览:https://golang.org
      [失败] https://nonexistent.example.com:Get "https://nonexistent.example.com": dial tcp: ...
      所有网页请求已完成。
      

      五、重点知识点讲解

      1. 使用 Goroutine 启动并发请求

      go fetchURL(url, &wg, resultCh)
      

      每个网页请求都是一个轻量级的线程(协程),同时运行,编程客栈最大化资源利用。

      2. 使用 sync.WaitGroup 等待所有任务完成

      WaitGroup 是 Goroutine 的最佳搭档,确保主线程不会提前退出。

      wg.Add(1)
      defer wg.Done()
      

      3. 使用带缓冲的android Channel 收集结果

      resultCh := make(chan Result, len(urls))
      

      避免协程阻塞,收集所有结果后统一处理。

      4. 设置请求超时

      使用 http.Client{ Timeout: ... } 可防止因某个 URL 卡住导致整体阻塞。

      5. 防止通道未关闭阻塞

      一定要在所有任务完成后关闭结果通道:

      go func() {
          wg.Wait()
          close(resultCh)
      }()
      

      六、可扩展方向

      这个简单的并发网页下载器可以继续扩展为:

      功能方向实现建议
      限制最大并发数使用带缓冲的 chan struct{} 控制令牌
      下载网页保存文件使用 os.Create 写入 HTML 文件
      支持重试机制封装带重试的请求逻辑
      使用 context 控制取消或超时实现更复杂的任务调度系统
      支持代理设置 Transport.Proxy 实现

      七、小结

      通过本篇案例你掌握了:

      • 使用 Goroutine 启动并发任务
      • 使用 Channel 汇总任务结果
      • 使用 WaitGroup 管理协程生命周期
      • 网络请求的错误处理与超时机制

      这为你实现一个功能完善的高并发爬虫、网页检测器或 API 批量处理工具奠定了基础。

      以上就是Go语言实现多协程并发下载网页内容的完整代码的详细内容,更多关于Go多协程并发下载网页内容的资料请关注编程客栈(www.devze.com)其它相关文章!

      0

      上一篇:

      下一篇:

      精彩评论

      暂无评论...
      验证码 换一张
      取 消

      最新开发

      开发排行榜