讲师中心 微信公众号
AI工具推荐 视频效率加速

Golang并发爬虫架构设计_多协程URL调度与去重

小萱同学_8269

小萱同学_8269

发布时间:2026-02-25 17:40:58

|

961人浏览过

|

来源于php中文网

原创

用 sync.Map 做 URL 去重会出问题,因其不保证“写入即可见”,新协程可能读不到刚存的 URL;正确做法是用 LoadOrStore 并检查返回的 bool 值判断是否首次存入。

golang并发爬虫架构设计_多协程url调度与去重

为什么用 sync.Map 做 URL 去重会出问题

并发爬虫里最常踩的坑是:把 sync.Map 当成万能去重容器,结果漏爬或重复请求。它确实线程安全,但不保证「写入即可见」——新协程可能读不到刚存进去的 URL,尤其在高频插入+快速判断的场景下。

真正该用的是带原子语义的「判存并设」操作。Go 标准库没直接提供,得自己封装:

  • sync.Map.LoadOrStore(url, struct{}{}) 返回值第二个 bool 才表示「本次是首次存入」,必须检查这个布尔值,不能只看第一个返回值
  • 如果用 sync.Map.Store + sync.Map.Load 两步走,中间必然存在竞态窗口,URL 会被重复调度
  • 高吞吐下 sync.Map 的哈希冲突会导致性能抖动,实际压测发现比 map + sync.RWMutex 慢 15%~30%

如何让多个协程安全地从队列取 URL

别用 chan string 直接当任务队列——一旦消费者协程 panic 或提前退出,未消费的 URL 就永远卡在 channel 里,后续无法回收或重试。

推荐用带状态管理的「工作池模式」:

立即学习“go语言免费学习笔记(深入)”;

Golang Uber Dig
Golang Uber Dig

使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等

下载
  • 用 sync.Pool 缓存 url.URL 实例,避免高频分配 GC 压力
  • URL 调度器内部维护一个 list.List + sync.Mutex,出队时先 mutex.Lock(),取完立即 mutex.Unlock(),不等解析完成再释放锁
  • 每个协程取到 URL 后,立刻调用 markInFlight(url)(用 sync.Map 记录 in-flight 状态),防止超时重试时被其他协程重复领取

context.WithTimeout 在 HTTP 请求里为什么总失效

不是 context 不生效,而是很多人只给 http.Client 设了 Timeout,却忘了给单次请求传 context。结果是:全局超时起作用,但单个请求卡死在 DNS 解析或 TLS 握手阶段,context 根本没机会触发取消。

正确做法是两者都配:

  • http.Client 的 Timeout 控制整个请求生命周期(含重定向)
  • 每次 client.Do(req.WithContext(ctx)) 必须传入带超时的 ctx,否则 DNS/TLS 阶段不响应 cancel
  • 如果用了自定义 Transport,还要确保 DialContext 和 TLSHandshakeTimeout 也基于同一 context

Redis 做分布式去重时,SETNX 和 SET ... NX EX 差在哪

本地单机用 sync.Map 还能凑合,一上分布式就暴露问题:SETNX 只能设 key,没法同时设过期时间,导致机器宕机后 key 永久残留,整个爬虫系统停摆。

必须用原子命令一次性完成「设值 + 过期」:

  • SET url:xxx "1" NX EX 3600 是唯一可靠方案,NX 保证不存在才设,EX 防止 key 永驻
  • 不要用 GET + SET 两步,网络分区时可能产生脏数据
  • 如果 Redis 版本 SET 不支持 NX EX 组合,得降级用 Lua 脚本封装 redis.call("SET", KEYS[1], ARGV[1], "NX", "EX", ARGV[2])

去重逻辑越往后越容易被忽略:URL 归一化(去掉 fragment、统一 scheme)、子域名归并(a.example.com 和 b.example.com 是否算同站)、以及重试时要不要跳过已失败过的 URL —— 这些不写进调度器核心,光靠外围补丁很难兜住。

热门AI工具

更多
咔片AIPPT

一款在线AI演示文稿制作工具,可根据主题和内容需求辅助生成PPT结构与页面,提高演示材料制作效率。

立刻MV
立刻MV Hot

立刻MV是一款AI文本写作工具,AI 音乐视频(MV)创作工具。

VibeKnow
VibeKnow Hot

一款AI视频创作工具,主要用于全球首个AI知识视频创作平台,文档、文章、网页,一键生成视频,适合需要提升相关任务效率的用户。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

SkildArt
SkildArt Hot

SkildArt是一款AI文本写作工具,一站式 AI 视觉创作平台。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

火山引擎

火山引擎是一款面向企业的云计算与AI服务平台。

Seko
Seko Hot

一款AI视频创作工具,主要用于商汤科技推出的创编一体的AI短视频创作Agent,适合需要提升相关任务效率的用户。

相关专题

更多
golang如何定义变量
golang如何定义变量

golang定义变量的方法:1、声明变量并赋予初始值“var age int =值”;2、声明变量但不赋初始值“var age int”;3、使用短变量声明“age :=值”等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

519

2024.02.23

golang有哪些数据转换方法
golang有哪些数据转换方法

golang数据转换方法:1、类型转换操作符;2、类型断言;3、字符串和数字之间的转换;4、JSON序列化和反序列化;5、使用标准库进行数据转换;6、使用第三方库进行数据转换;7、自定义数据转换函数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

596

2024.02.23

golang常用库有哪些
golang常用库有哪些

golang常用库有:1、标准库;2、字符串处理库;3、网络库;4、加密库;5、压缩库;6、xml和json解析库;7、日期和时间库;8、数据库操作库;9、文件操作库;10、图像处理库。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

1176

2024.02.23

golang和python的区别是什么
golang和python的区别是什么

golang和python的区别是:1、golang是一种编译型语言,而python是一种解释型语言;2、golang天生支持并发编程,而python对并发与并行的支持相对较弱等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

791

2024.03.05

golang是免费的吗
golang是免费的吗

golang是免费的。golang是google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的开源编程语言,采用bsd开源协议。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

1726

2024.05.21

golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

4914

2025.06.09

golang相关判断方法
golang相关判断方法

本专题整合了golang相关判断方法,想了解更详细的相关内容,请阅读下面的文章。

2274

2025.06.10

golang数组使用方法
golang数组使用方法

本专题整合了golang数组用法,想了解更多的相关内容,请阅读专题下面的文章。

4146

2025.06.17

Gradle插件开发入门教程
Gradle插件开发入门教程

本专题介绍Gradle插件开发的基本流程,涵盖插件类编写、自定义任务注册、扩展参数设计和插件应用方法,帮助你理解插件如何组织构建逻辑,减少多个项目之间的重复配置。

60

2026.10.22

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn