当前位置: 首页 > news >正文

Go语言实战案例:多协程并发下载网页内容

本文是《Go语言100个实战案例 · 网络与并发篇》第6篇,实战演示如何使用 Goroutine 和 Channel,实现多协程并发抓取网页内容,提升网络请求效率,为构建爬虫、内容聚合器、API 批量采集器打下基础。


一、实战背景

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

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

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


二、实战目标

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

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

三、完整代码实现

package mainimport ("fmt""io""net/http""strings""sync""time"
)type Result struct {URL    stringStatus stringLength intError  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.WaitGroupresultCh := make(chan Result, len(urls))// 启动多个下载协程for _, url := range 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. 使用带缓冲的 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 批量处理工具奠定了基础。

http://www.dtcms.com/a/313578.html

相关文章:

  • 《 ThreadLocal 工作机制深度解析:高并发场景的利与弊》
  • Mysql深入学习:InnoDB执行引擎篇
  • C++ : 反向迭代器的模拟实现
  • 【图像处理基石】如何使用deepseek进行图像质量的分析?
  • vllm0.8.5:思维链(Chain-of-Thought, CoT)微调模型的输出结果包括</think>,提供一种关闭思考过程的方法
  • MCP协议:CAD地图应用的AI智能化解决方案(唯杰地图MCP)
  • 【数据结构与算法】数据结构初阶:排序内容加餐(二)——文件归并排序思路详解(附代码实现)
  • 【C++】面向对象编程
  • C语言(长期更新)第8讲 函数递归
  • 网络通信与Socket套接字详解
  • C#模式匹配用法与总结
  • 网页 URL 转 Markdown API 接口
  • 大模型中的Token和Tokenizer:核心概念解析
  • 【Unity3D实例-功能-镜头】俯视角
  • MySQL极简安装挑战
  • 数据结构代码
  • IO流-数据流
  • 语义分割--deeplabV3+
  • 企业级AI Agent构建实践:从理论到落地的完整指南
  • 机器学习中的经典算法
  • 算法讲解--最大连续1的个数
  • C++异常与智能指针,资源泄露
  • CMake 命令行参数完全指南
  • 【动态规划算法】路径问题
  • kubernetes基础知识
  • Linux命令基础(下)
  • Day22--回溯--77. 组合,216. 组合总和 III,17. 电话号码的字母组合
  • 深入剖析Java拦截器:从原理到实战
  • Python3 中使用zipfile进行文件(夹)的压缩、解压缩
  • 一加Ace5无法连接ColorOS助手解决(安卓设备ADB模式无法连接)