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

53 天前
 lsk569937453

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

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

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

8539 次点击
所在节点    程序员
103 条回复
trzzzz
53 天前
@Ashe007 试一下 [文件] -> [内存] -> [oss-sdk] 。你分段上传的 [源文件] 是分片好的吗,如果是已经切好片了你把 file 丢给 sdk 也没问题,它也会一点点传走
mayli
53 天前
@kenvix 你以为这样的程序员是段子?他其实是认真的,就感觉没啥讨论下去的意义。
mayli
53 天前
大部分程序员,可能对网络和文件系统接口都不熟。
现代操作系统提供的网络基本上都不会出现传输错误,现代操作系统也都会提供 seek+随机写的功能。
对于 preallocate 会有各种实现方式,不过提供的结果基本一致,也就是实现了随机写。另外,即使不依赖 seek ,也可以有 mmap 这样的方式实现随机写。
再说从网络下载到磁盘,大部分操作系统也会提供 zero-copy 或者类似 pipe 的功能,即使没有,IO 操作时基本上也是使用一个固定 buffer ,比如 64k ,不会把全部内容放到内存再操作。
再说一下状态恢复,类似数据库一样,分片的下载状态一般是单独存放,比如 aria 、flashget 或者迅雷,只有分片下载完成后再去更新状态,这样即使程序崩溃,也可以下次启动从恢复点续传。
最后补充一个极端的例子,BT 下载每次传输单元是 16KB ,难不成要创建一堆 16KB 的文件,然后完成之后再合并?从文件系统的效率角度来说,从 socket 读并且单独写入一个大文件,这里可以只需要频繁调用 read(socket) + write(fd)。 但是如果是一堆小文件,你需要频繁创建和关闭文件,这两个操作在大部分操作系统,尤其是 HDD 上的文件系统,开销会非常大,你的顺序写操作会变成随机写,同时如果你的操作系统安装了杀毒软件,杀软也会在文件关闭时进行扫描,结果就是更慢了。

一般程序员在软件设计和实现的时候,都会倾向于使用资源需求最小并且吞吐量高的方案。所以当小文件没有明显优势,而且特殊场景下资源开销和性能都有明显损耗的情况下,选择大文件是一个比较自然的方案。

类似的需求还有比如数据库,就像如果网络客户端发送了一些 INSERT ,你是把他们写入小文件然后再合并呢,还是直接放到大文件中。这里的就会有和网络下载类似的权衡,当然也有不一样的地方。
cybort
53 天前
不是所有文件系统都支持你预分配空间加稀疏存储的,你得前置写入一遍磁盘,给用户的感觉就是启动延迟。
cybort
53 天前
那天找到一个远古的 bt 软件,就是下载成很多小块文件的。另外小水管时代每个小块下载都很慢,这样也方便单独做文件校验。
msg7086
53 天前
@w568w 你可能搞混了 preallocation 和 sparse file 。
你说的写多少用多少是 sparse file ,而快速 allocation 是立即分配你申请的空间但不初始化成零。
以前那种下载大文件要卡很久,不是因为申请空间慢,而是申请空间的时候需要清零所以慢。快速 alloc 本质上是跳过清零空间。(也意味着这种分配方式需要提权,因为跳过了清零,所以程序可以读到磁盘上原本他看不见的已删除数据。)

为了减少文件碎片,肯定是一次性分配整个文件的空间更划算。
lamquan
53 天前
支持楼主,因为每次下载几十 G 的大文件,IDM 合并都慢死了,对磁盘读写消耗也大。
guo4224
52 天前
@huixia0010 这两种方式都不可以呀
w568w
52 天前
@msg7086 谢谢提醒。你是对的,我确实弄混了。
llsquaer
52 天前
@msg7086 我就觉得这个是当年的神器。不知为啥现在没了。不知道和 IDM 原理有区别么?都是分块下载
msg7086
52 天前
@llsquaer P2P 下载方式起来了以后这种就没什么用了。这些软件都是在 56k 网络的时候才有用,下一个文件要下几十分钟甚至几小时。现在网速是原来的一万倍,没意义了。
msg7086
52 天前
另外这软件还有自动拨号和下载完成自动挂断的功能,对拨号的用户实在是太友好了。
IXTUS
52 天前
bt ?
digimoon
52 天前
没想到这么多年了 idm 还是那么菜
pubby
52 天前
图省事吧,代码写起来简单,几个文件写入流,无脑 write 就行
性能上没啥差别,尤其现在都用固态了
jiezhi
52 天前
还一个除了本地文件系统是不是所有的文件系统单文件都支持多并发写入?
我知道的 hdfs 是只支持追加和复写,不支持寻址写。
trzzzz
52 天前
@jiezhi hdfs 复写也可以复写一段范围的数据吧
wuxianliang
52 天前
IDM 俗称单线程下载之王...
Inn0Vat10n
52 天前
题外话,有些存储/driver 实现,并发读写多文件是要比并发读写单文件快的,比如英特尔的 AEP , 不过下载这个场景瓶颈大概率在网络 IO
aeof
52 天前
编程小白,能帮忙看看实现有什么问题不: https://aeof.tech/posts/demo/multi-thread-downloader/

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

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

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

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

© 2021 V2EX