C++多线程实现多任务并行的Web爬虫引擎

千宇吖_6973

千宇吖_6973

2026-09-20

572人浏览

原创

必须用std::mutex+std::lock_guard保护所有共享容器;libcurl需设curlopt_nosignal=1l、超时参数及curlopt_tcp_keepalive;std::thread须join();url去重推荐布隆过滤器+归一化。

c++多线程实现多任务并行的web爬虫引擎

std::thread 启动爬虫任务时,如何避免资源竞争和连接泄漏

直接用 std::thread 拉起多个 std::function 去抓 URL,最容易出问题的不是并发数,而是共享资源没加锁、HTTP 连接没显式关闭、异常路径没回收句柄。

典型表现:程序跑几分钟后卡住,netstat -an | grep :80 显示几百个 TIME_WAITESTABLISHED;或者 std::vector<:thread></:thread> 析构时报 std::system_error: Resource deadlock avoided

  • 所有共享容器(如待抓队列、已抓 URL 集合、结果缓存)必须用 std::mutex + std::lock_guard 保护,别依赖“我只读不写”这种假设
  • 每个线程内使用 libcurl 时,务必在每次请求后调用 curl_easy_cleanup();若复用 CURL* 句柄,需确保同一句柄不跨线程使用
  • std::thread 对象必须在析构前调用 join()detach() —— 更推荐 join(),配合 std::vector<:thread></:thread> 的 RAII 管理

用 std::async + std::future 控制并发上限,比裸 thread 更稳

std::async 默认可能启动新线程,也可能延迟执行,但配合 std::launch::async 和线程池封装,能更可控地限制并发请求数。它天然解决 std::thread 的生命周期管理难题,也避免手动传参导致的引用悬空。

常见误用:auto f = std::async([]{ /* long IO */ }); 忘记取 f.get(),导致 future 析构时阻塞等待——这会让“异步”变成“同步串行”。

  • 并发上限建议硬编码为常量(如 const int MAX_CONCURRENCY = 10),用 std::queue<:future>></:future> 缓存活跃任务
  • 每次提交新任务前,先 wait_for(0s) 检查已有 future 是否就绪,未就绪则 pop 掉已完成的,保持队列长度 ≤ MAX_CONCURRENCY
  • 别把 std::string_view 或局部 std::string 直接捕获进 lambda:用值捕获或显式 std::move,否则抓到的是野指针

libcurl 多线程下 CURLOPT_NOSIGNAL 必须设为 1L

libcurl 默认启用信号处理(比如超时时发 SIGALRM),但在多线程环境里,信号可能被错误线程接收,导致整个进程 crash 或挂起。这是 C++ 爬虫最隐蔽的崩溃源之一。

C++
C++

"空空如也"

下载

现象包括:偶发段错误、curl_easy_perform() 返回 CURLE_ABORTED_BY_CALLBACK 却没触发回调、或某次请求后整个线程卡死无响应。

  • 每个 CURL* 句柄初始化后立即设置:curl_easy_setopt(handle, CURLOPT_NOSIGNAL, 1L)
  • 同时必须设置超时参数:curl_easy_setopt(handle, CURLOPT_TIMEOUT, 30L)curl_easy_setopt(handle, CURLOPT_CONNECTTIMEOUT, 10L),否则 NOSIGNAL 关闭后超时机制失效
  • 禁用信号后,DNS 解析仍可能阻塞(尤其在 glibc 低版本),可额外加 curl_easy_setopt(handle, CURLOPT_DNS_CACHE_TIMEOUT, 60L) 减少重复查询

URL 去重与调度不能只靠 std::set<:string>

单纯用 std::set<:string></:string> 存已访问 URL,内存涨得飞快,且无法处理语义等价(如 /a?b=1&c=2/a?c=2&b=1)。更麻烦的是,多线程下 insert() + count() 不是原子操作,会漏判重复。

实际部署中,一个百万级种子 URL 的爬虫,std::set 内存占用常超 2GB,而布隆过滤器(Bloom Filter)加归一化处理能把内存压到 50MB 以内。

  • URL 归一化至少做三件事:转小写、移除默认端口(:80/:443)、排序并标准化 query 参数
  • 去重逻辑必须封装成原子函数,例如 bool should_crawl(const std::string& url),内部用 std::mutex 保护布隆过滤器 + 小规模 LRU cache(用于近期高频碰撞检测)
  • 别用 std::unordered_set 替代 —— 它的桶锁粒度太粗,高并发下性能反而不如加锁的 std::set,而布隆过滤器无锁且 O(1)

实际跑起来你会发现,瓶颈从来不在并发模型本身,而在 DNS 解析阻塞、TCP 连接复用率低、SSL 握手开销,以及——没人告诉你 libcurl 的 CURLOPT_TCP_KEEPALIVE 默认是关的。

C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!

相关专题

更多
c++和c语言的区别有哪些
c++和c语言的区别有哪些

c++和c语言的区别:1、面向对象编程(OOP)支持不同;2、新增特性不同;3、标准库不同;4、编译方式不同;5、命名空间不同等等。想了解更多c++的相关内容,可以阅读本专题下面的文章。

2024.03.14

2068

9

c++和python学习顺序推荐
c++和python学习顺序推荐

一般建议先学习C++,再学习Python,因为这样可以逐步从较为底层的编程语言向更高级的语言过渡。想了解更多python的相关内容,可以阅读本专题下面的文章。

2024.03.14

939

6

python和c++学习性价比分析
python和c++学习性价比分析

Python易于学习,广泛应用于Web开发、数据科学和人工智能等领域,但性能较低。C语言性能高,适用于对性能要求较高的场景,如游戏开发和系统编程,但学习曲线陡峭,错误处理复杂。想了解更多python的相关内容,可以阅读本专题下面的文章。

2024.03.14

367

5

c语言和c++一样吗
c语言和c++一样吗

c语言和c++是两种不同的编程语言,虽然有相似之处,但存在显著差异。c语言专注于过程式编程和系统级开发,以简洁、高效著称。c++作为c语言的超集,引入了面向对象编程,增强了代码组织和管理能力,但学习曲线也更陡峭。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.03.14

307

5

c语言和c++先学哪个好
c语言和c++先学哪个好

初学者选择学习c语言还是c++语言,需要根据个人学习目标、背景以及编程兴趣和预期应用方向来决定。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.03.14

346

5

c语言和c++的区别和联系
c语言和c++的区别和联系

c语言和c++是计算机科学领域应用广泛的编程语言。虽然它们有着相似的基础,但它们在语言类型、语法功能和内存管理方面存在着显著差异。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.03.14

560

5

c++软件中文更改教程
c++软件中文更改教程

对于 ide,可通过打开设置,找到语言设置,选择中文,并保存更改。对于非 ide 应用程序,可查找设置或选项,选择语言设置,更改为中文,并保存更改。想了解更多c++的相关内容,可以阅读本专题下面的文章。

2024.03.21

1389

9

python和java和c++学习性价比分析
python和java和c++学习性价比分析

Python以其易学性、丰富的库和活跃的社区而著称,适合数据科学、人工智能和Web开发。Java以其跨平台性、企业级应用开发和Android应用开发而闻名。C++以其底层控制能力、高效性能和游戏开发而著称。选择哪种语言取决于个人兴趣、职业方向和特定需求。想了解更多python和java和c++的相关内容,可以阅读本专题下面的文章。

2024.03.22

1177

7

c++和c语言学习顺序推荐
c++和c语言学习顺序推荐

对于初学者,建议先学习C语言,掌握编程基础后再转入C++,便于理解面向对象编程概念。有编程经验者可直接学习C++,快速接触高级编程技术。想了解更多c++和c语言的相关内容,可以阅读本专题下面的文章。

2024.03.25

1305

9

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Valgrind Quick Start Guide
Valgrind Quick Start Guide

共0课时 | 0人学习

CLion CMake 快速入门教程
CLion CMake 快速入门教程

共0课时 | 0人学习