多线程分段下载文件时,为什么不下载到同一个大文件中?而是要分别下载到单独的文件然后再合并。

207 天前
 lsk569937453

https://gist.github.com/lsk569937453/e0496754cf3ebe740a33a7759516015e

我自己写了个 demo ,假设开 50 个线程下载,每个线程下载时间为 10s 钟,可以看到最后写入文件的时间才 1s 不到。

所以下载文件时,瓶颈是网络 IO 吧,操作文件 IO 的时间可以忽略不计了。所以是不是下载到一个文件中更优?

11609 次点击
所在节点    程序员
103 条回复
guanzhangzhang
207 天前
因为好多人只管实现,不管细节地方
多线程下载,他肯定会下意识想会有问题冲突占用问题,所以我多个文件合并就行了。
而不是去想和搜搜看怎么多线程同时写一个文件互不影响。

例如临时文件,很多人直接放/tmp 下,而不是使用 mktemp
例如一个 daemon 进程,很多人和运维( ansible 部署 java 里)都是 nohub 启动,而不是写 systemd
你指出来,他们就会💩叫”又不是不能用“
huixia0010
207 天前
如果下载的是不清楚长度的流媒体直播流呢?
nolog
207 天前
@guanzhangzhang #21 不懂就问,用 nohup 有什么不好的地方吗?
Maerd
207 天前
因为实现起来通常更简单,也更容易处理错误和恢复下载
Ashe007
207 天前
说一个都没有关注的关键点:内存溢出,如果服务器剩余可用内存为 4 个 G ,文件为 5G 。拆分就是避免内存溢出的场景,因此大文件才需要分段上传/下载。
如果文件是可预料的小,当然没必要拆分
FranzKafka95
207 天前
@nolog nohub 当然没有 systemd 好,systemd 功能可高级多了
Ashe007
207 天前
此外,还减轻了网络压力和内存压力,降低了系统负载
monkeyWie
207 天前
这个我作为 gopeed 下载的作者可以答一下,上面有 v 友其实也已经说的很对了,分多个临时文件下载再合并就是一种垃圾实现,没错就是说的 IDM ,预分配 + seek 写才是正确的高性能的对硬盘损耗最小的。
aababc
207 天前
@guanzhangzhang 又学了点新知识,mktemp 这个还从来没用过
cheng6563
207 天前
Windows 需要管理员权限才能预分配大文件空间吧。
0312birdzhang
207 天前
完全可以,先根据 content-length 创建好文件大小,再分片写入(重写)就行了。同时写入一个文件和同时写入多个文件,对磁盘来说是一样的吧。
guanzhangzhang
207 天前
@nolog nohub 启动,进程意外退出就 g 了,systemd 有重试,cgroup ,前后顺序依赖,io 限制,条件启动,
guanzhangzhang
207 天前
@aababc 如果写单元测试,好多就是语言里库的 mktmp 啥的方法创建临时文件或者目录
shuax
207 天前
也就只有 IDM 才这样吧。我再来个暴论,多线程也是不需要的,完全可以单线程实现多并发。
lesismal
207 天前
@kenvix
如果写到多个文件, 每个文件可以自带上一个元信息, 即使任务中途失败导致下载器退出之类的, 以后还可以从上次下载的地方继续. 直接写入到目标文件, 没有这个元信息, 如果中途失败退出了, 下次只能从头来.
对于大文件低带宽不稳定, 不能确保单次操作下载完的情况下, 直接写目标文件不划算;
而即使是 10G 这种大文件, 本地多个分段文件做一次合并的开销和耗时也几乎可以忽略不计.

另外, 分段下载如果对方响应的数据不是 trunked, 而是 content-length, 不同平台或许还可以利用 zero copy 优化避免先读取到内存再写入文件, 既减少应用层内存开销也提高速度, 多线程直接写入 queue 再写入目标文件的方式不好做这些. 不过这些本地 io 和只是读写 buffer 的内存开销本来也不大, 即使能做提升也不会太大.
lisxour
207 天前
省流版

小文件分片:逻辑简单易实现,会多一点时间、性能消耗( 2024 年了,完全可以忽略)
单文件:逻辑相对复杂点,要求对多线程 io 操作有一定了解,作为用户而言(我自己),没发现什么很明显的体验提升,迅雷、百度云就是单文件的,其实也就那样
auroraccc
207 天前
是的,多文件合并还得花时间,不如直接把多个分片写到一个文件的不同 range 里
lovezhangdada
207 天前
@monkeyWie
老师,我想请教一下 aria2 和 gopeed 实现原理一样吗》?
kenvix
207 天前
@lesismal #35 关于续传,他没问我也就没说,实现上一般有一个 bitmap 控制文件写入情况,你说的所有问题用一个 bitmap 就能解决了。另外如果不想用 bitmap ,创建的时候指定文件类型为稀疏,然后直接询问系统哪些块是稀疏的,直接从稀疏块开始,也是可以的。
kenvix
207 天前
@Ashe007 #25 你直接把文件全量放到内存里?

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1039715

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX