应使用带缓冲的channel控制并发数,如sem := make(chan struct{}, 10),每次下载前<-sem、完成后sem<-struct{},避免goroutine泄漏导致OOM。
goroutine 泄漏导致内存爆满怎么办
不加限制地起
,几万张图下来进程直接 OOM。根本原因不是下载慢,是没等下载完协程就挂了,但 HTTP 连接、响应体缓冲、甚至未回收的
实例还在占内存。
必须用带缓冲的 channel 控制并发数,比如
,每次下载前
别复用全局
时忽略
和
,否则 DNS 缓存+连接池会悄悄吃光句柄
用
包裹每个请求,防止某张图卡死拖垮整个池
文件名冲突和路径安全怎么处理
直接用 URL 的
当文件名,遇到
就生成
,Linux 下创建失败,Windows 直接报错
。
用
解析后取
,再用
;接着用
去掉查询参数干扰
对结果做一次
防止
路径穿越,再用正则替换非法字符:
→
保存前先
,别假设目录一定存在
下载失败后如何重试又不阻塞池子
单次失败就
,会导致任务丢失;全量重试又可能把超时请求反复塞进池子,压垮目标站或自己。
每张图最多重试 2 次,用
每次重试前加
失败日志里必须打上原始
和
,否则排查时根本不知道哪张图卡在哪一步
别在重试逻辑里直接
—— 协程池已负责调度,重复起 goroutine 就破防了
为什么用
而不是
会把整张图读进内存再写文件,10MB 的图 × 10 并发 = 至少 100MB 内存常驻;而大图下载场景下,内存占用比 CPU 更早成为瓶颈。
go语言参考手册 中文CHM版
Go 是一个开源的编程语言,它能让构造简单、可靠且高效的软件变得容易。本文给大家带来Go参考手册,需要的可以来下载! Go是从2007年末由Robert Griesemer, Rob Pike, Ken Thompson主持开发,后来还加入了Ian Lance Taylor, Russ Cox等人,并最终于2009年11月开源,在2012年早些时候发布了Go 1稳定版本。现在Go的开发已经是完全开放的,并且拥有一个活跃的社区。 Go 语言特色 简洁、快速、安全 并行、有趣、开源 内存管理、v数组安全、编译
下载
立即学习
“
go语言免费学习笔记(深入)
”;
直接
,数据流式写入磁盘,内存峰值只取决于 OS page cache 大小
记得在
前设好
或用
标志(视可靠性要求而定),否则断电可能丢最后几 KB
如果要校验 MD5/SHA256,用
,边读边算,不额外加载
事情说清了就结束。真正难的不是起十个协程,是让它们在出错、超时、路径异常、磁盘满、对方限速时,依然不泄漏、不卡死、不污染输出目录。
go downloadImage(url)http.Clientsem := make(chan struct{}, 10)sem ,结束后 <-semhttp.ClientTimeoutTransport.MaxIdleConnsPerHostcontext.WithTimeout(ctx, 30*time.Second)path.Base()https://i.example.com/1?w=800&h=6001?w=800&h=600invalid argumenturl.Parse()u.Pathpath.Base(u.Path)strings.TrimSuffix()filepath.Clean()../re := regexp.MustCompile(`[:"/\|?*]`)re.ReplaceAllString(name, "_")os.MkdirAll(dir, 0755)returnfor i := 0; i 包裹核心逻辑,成功就 breaktime.Sleep(time.Second (即 1s、2s、4s),避免雪崩式重试urlerr.Error()go download(...)io.Copyio.ReadAllio.ReadAll(resp.Body)io.Copy(f, resp.Body)io.Copyf.Sync()os.O_SYNCio.TeeReader(resp.Body, hashWriter)