问题

多线程下载一个大文件的速度更快的真正原因是什么?

回答
咱们聊聊这多线程下载大文件为啥就比单线程快?这可不是什么玄乎的魔法,说白了,就是把一项大工程分解,让好几个人(线程)同时干活,效率自然就上去了。不过,这背后的门道可不少,咱们就一点点捋清楚。

首先得明白,网络传输和计算机内部处理,都有一个叫“带宽”和“处理能力”的东西。

一、突破单点瓶颈:

想象一下,你一个人在搬砖,一次只能拿一块砖。如果有很多砖要搬,你一个人搬到天黑也搬不完。

单线程下载: 就像一个人在下载,一次只能建立一个网络连接,从服务器请求一小块数据,然后接收、处理。这个过程就像你一次拿一块砖。如果服务器的响应速度够快,你的电脑处理速度也够快,但这个网络连接本身可能就是一个“瓶颈”。服务器可能还有很多其他连接,它分配给你的连接速度有限。或者,你的电脑网卡处理能力有限,一次只能高效处理一个数据流。
多线程下载: 就像你请了几个壮汉来帮你搬砖,每个人一次拿一块砖,但因为人多,搬砖的总速度就快多了。在下载时,多线程就是同时建立多个网络连接,每个线程负责下载文件的一个不同部分。这样,即使单个连接的速度受限,多个连接加起来的总速度就能大大提高。

二、更充分地利用网络带宽:

这就像一条很宽的公路,你开一辆车,虽然车速很快,但因为只能容纳一辆车,所以整条路的利用率并不高。

单线程下载: 就像这条公路上只跑一辆车。即使你的网络带宽很高(就像这条路可以容纳很多车),单线程也只能利用其中的一部分。很多时候,下载速度的上限并不是你电脑有多快,而是你的网络连接到底能传输多少数据。
多线程下载: 就像在这条宽阔的公路上同时跑多辆车。每个线程就像一辆车,它们可以同时在网络这条“公路”上行驶,更充分地利用了你的总带宽。如果你的网络总带宽是100MB/s,理论上你可以用多个线程加起来达到这个速度,而不是被单个连接限制在比如10MB/s。

三、克服服务器和网络延迟:

网络传输不是瞬时的,数据包从服务器传到你这里,需要时间,中间可能还要经过很多路由器。

单线程下载: 当一个数据包发送出去后,需要等待服务器的响应,然后才能发送下一个数据请求。这个等待的过程,尤其是在网络延迟较高的情况下,会浪费很多时间。就像你问一个问题,等对方回答了才能问下一个问题,期间的等待是低效的。
多线程下载: 线程之间是独立的,一个线程在等待服务器响应时,其他线程可以同时在发送请求或者接收数据。这就好像你有多个助手,当你问一个人问题时,你的其他助手可以继续在做自己的事情,不让你一个人傻傻地站着。这有效地“隐藏”了网络延迟,让整体吞吐量更高。

四、缓存和数据处理的优化:

虽然不是主要原因,但有时候多线程也能带来一些协同效应。

单线程下载: 接收到的数据需要被处理、写入磁盘。如果处理速度跟不上接收速度,就会出现缓冲区溢出或者等待处理的情况。
多线程下载: 不同的线程可以并行地处理接收到的数据块,比如一个线程负责接收,另一个线程负责解压缩(如果文件压缩了),还有一个线程负责写入磁盘。这种并行处理能力可以进一步提升下载效率。当然,这也要看下载软件本身的优化设计。

打个更形象的比方:

想象一下你在一个大型图书馆找一本书。

单线程: 你一个人,从入口开始,一本一本地翻阅书架,找到就拿走。如果书很多,查找就很慢。
多线程: 你请了几个朋友,你们分成几组,分别负责不同的区域(比如一层、二层、三层),每个人找到自己的目标就拿走。即使每个人速度差不多,但因为分区域同时找,整个找书的速度就快多了。

当然,多线程下载也有限制:

1. 服务器端限制: 服务器可能不允许同一个IP同时建立过多连接,否则会限制你的总速度。
2. 电脑性能: 虽然不是瓶颈,但过多的线程也会消耗一定的CPU和内存资源。
3. 软件设计: 下载软件本身需要做好线程管理和数据合并工作,否则线程越多反而越乱。

总的来说,多线程下载之所以更快,核心原因在于它能够更充分地利用网络带宽、规避单点瓶颈、以及在一定程度上克服网络延迟,通过并行处理来提高整体的数据传输效率。这就像让一支队伍同时推进,而不是一个人孤军奋战。

网友意见

user avatar

我来说个大家没有讲到的方面吧……


当然,链路带宽、滑动窗口这些都对,甚至可能是主因。

但还有一个不太能想到的问题是,其实服务器不一定只有一台……

但是每个TCP连接通常只能连到确定的一台服务器。你多开几个线程,其实可能多了几台服务器给你服务……

这也是我喜欢客户多开几个线程下载的原因……

user avatar

这要根据网络实际情况分别讨论。胡乱归咎于滑动窗口是不负责任的。

根据我的经验,这个问题起码要分六个大类分别讨论——这六大类讨论完毕,还得再说说流控算法的公平性问题。


1、低延迟网络

低延迟网络指的是相对于网络最高带宽,信息传输延迟很低、不至于影响数据最高传输率的网络。

一般来说,这类网络无需考虑滑窗算法问题。

这是因为,除非局域网内部之类点对点传输的场景,一旦经过了路由器之类网络设备,数据传输就一定会被途中每个设备的缓冲区影响;一旦触发流控就说明缓冲区已经爆了、主动丢包了;那么此时“滑窗大小主动减半然后线性增长”其实起了“等待缓冲区清空”的作用,并不会严重影响设备吞吐率。

而点对点传输场景呢,正常来说链路层都有个码率协商过程;一旦协商成功,那就是“只要你能放到线路上对方就一定能接的住”,不涉及缓冲区也不会丢包(除非线路稳定性不足)——此时TCP的流控基本不起作用,设备压根就是一直压着线路最高传输速率跑。

1.1 无限速

实际网络上,你往往需要和其他用户共用一段链路(共用路由、共用小区光纤等等);此时多线程下载主要和资源竞争相关。

无限速条件下,你要和其他用户竞争使用同一条链路。当你传输信息时,其他用户就不得不等待;其他用户传输时,你也不得不等待。

大多情况下,路由器或其他智能网络设备公平调度每一条链路;当你多线程下载时,你名下的链路数就会增多,于是你得到调度的几率就按照你开的链路数线性增加——比如十个用户十条链路全部跑满的话,每个用户可以占有线路容量的1/10;但如果你开了三条链路,那么你一个人就占用了线路容量的3/12。这样你的下载速度自然就高了很多。

但这种情况会引起恶性竞争,使得每个人都盲目的多开链路,很快耗尽网络设备资源。

1.2 有限速

实际网络上可能存在很多限速策略。不同的限速策略、限速位置也会影响多线程下载的种种表现。

比如,服务器可能针对每用户限速;那么你开一百条链路也无法增加下载速度。

但这个策略太过复杂,实际上很难做到;所以网络供应商往往会为每个链接限速。那么你开N个链接自然就得到了N倍下载速率——但这实际上使得服务器为你一个人用了N倍的缓冲区空间,这是极其招人恨的。

因此,现在大多下载站限制每IP连接数,一般不允许超过3个。多开连接甚至可能被ban掉ip。


类似的,路由器也可以针对每个用户限速(此时多开连接并不增加下载速率);当你同时看视频并下载大文件时,这两个链接也会相互挤占带宽(这种挤占可能发生在你的PC终端以及途中的每个节点上)——所以当你BT下载同时看视频/玩游戏就可能卡顿。


总之,大多情况下,多开连接的确能挤占到更多的线路带宽;这或许就是很多人盲目多开连接搞多线程下载的原因所在——也是很多答案盲目的把“多开连接提高下载速率”归结于“滑动窗口”这个基础算法的原因。

但是,多开连接未必真能多挤占带宽。事实上,因为多开连接会过快消耗服务器资源,互联网工程师们反而花了很大精力去限制用户“借助多开连接得利”。


2、高延迟网络

随着网速提高以及跨国通讯业务增加,很多网络的延迟已经足以影响链路数据传输速率上限了。

这是因为,TCP需要借助“滑窗”这个缓冲区里面的数据实现重传、从而保证可靠通讯。具体说就是发送端必须收到接收端的确认报文(ACK)后,才敢废弃缓冲区里相应的数据。

设滑动窗口最大值为W字节,报文往返时间(发送端发送数据到收到对端返回的ACK报文所需的时间)为RTT,则数据最大传输率就等于 W/RTT。

对高延迟网络,RTT数值很大;那么如果W不够大,链路最大传输率就不可能高。

2.1 旧TCP协议的窗口大小

“滑窗”是要占用内存的;由于历史原因,TCP协议认为16位表示滑窗大小就足够用了。于是最大滑窗大小就只有64K字节。

在新兴的千兆光纤网(因为传输速率太高哪怕延迟很低也必须很大的滑动窗口才能跑满带宽上限)以及跨海电缆(延迟太高)上,这个大小实在太小了。因此后来不得不修改了协议,允许最高两个G的滑动窗口。

如果你用了很陈旧的操作系统的话,滑窗大小可能就有64K上限限制。这种情况下每条链路允许的最大传输率是远远跑不满线路容量的;此时多开链路相当于变相增大滑动窗口,传输速率自然增加。

2.2 新TCP协议的滑动窗口大小

当你的设备/操作系统的TCP协议栈不太旧时,虽然因为RTT过大导致滑动窗口大小增加不够快,但往往也只需若干秒就能跑到线路允许速率上限。此时情况和“低延迟网络”差别不大。


3、网络抖动

长距离数据传输时,尤其如3G/4G这样的公用无线信道很容易受到各种干扰,使得网络延迟(RTT)抖动。

3.1 低抖动网络

低抖动网络可按情形1、2讨论,不再重复。

3.2 高抖动网络

高抖动网络会严重影响流控算法,使得TCP滑窗大小不能按照预期增长。

当年我搞互联网链路聚合时做过实验,实验证明RTT在100~300ms间抖动时,TCP滑窗会很快停止增长,使得链路传输速率上限极低。这种抖动甚至比少量的丢包更能影响传输率(报文乱序造成大量DUP ACK时,链路传输率也会小幅下降,但影响也没有RTT剧烈抖动大)。

这种网络上,多开连接相当于人为强制加大滑窗大小,可以有效提高大文件下载速度。


4、流控算法的公平性

参与网络通讯的用户往往不止一个。那么,当不同用户使用不同流控算法时,它们是如何竞争带宽的呢?

比如说,UDP是不管报文有无丢失,只要网卡有空它就一刻不停的报文轰炸;而TCP呢,绝大部分流控算法会在报文丢失后主动降低数据传输率。那么,在一个UDP/TCP共存、且开足马力下载的网络环境里,TCP发送速率就会越来越慢。

换句话说,TCP会主动退让,而UDP不会。


类似的,不同的流控算法也有“是更倾向于侵占还是更倾向于退让”的不同“个性”。

那么不断开新连接、重复“慢启动”流程(慢启动是从很小的滑窗启动,速率是每RTT倍增的,反而是流控协议里增长最迅猛侵略性最强的阶段,增长一点都不慢)也能稍微多挤占一些资源;但后果是复杂的协商过程降低了线路上有效信息所占比率(一个TCP/IP头是带几个字节还是1K字节,带宽利用率显然是截然不同的),反而进一步恶化了通讯环境。

不仅如此,现在很多设备支持QoS优先级设置;比如游戏/视频之类延迟敏感的报文的优先级就可能高于文件下载。这种网络环境里,下载速率受到的影响就更为复杂了。


总结一下就是:

“多开线程增加下载大文件速率”大致来自于三个原因(或它们的组合):一是绕过不够严密的限速措施;二是在和其他用户/应用的竞争中挤占更多带宽;三是在高延迟高抖动网络里变相的强制增加滑动窗口大小,从而绕过TCP流控协议本身的缺陷。


除此之外,正常网络环境里,滑窗算法表现良好;多开线程反而会导致磁盘来回寻道、降低存储子系统吞吐率。在网络传输率和磁盘传输率基本匹配的应用环境里反而会造成负面影响(但大多情况下,硬盘传输带宽远大于网络带宽、再加上磁盘缓冲区的存在,因此最终影响不明显)。

user avatar

从二层看, 很多链路聚合算法不能做到基于 L4 hash, 这就会导致当你有两个链路的时候, 一个 TCP 连接只能在一个链路上, 只有多个 TCP 连接的时候才能有效利用. 当然拆分一个 TCP 连接到多个链路也是有风险的, 包不按照顺序到达会有性能损失.

从三层看, 可能一个下载的资源有多个地方的镜像, 比如一个域名解析出了多个地区的 CDN, 这个时候多线程就可以最大化本地 ISP 所能提供的带宽

从四层看, 单个 TCP 连接碰到不好的拥塞控制算法, 比如 Compound TCP/Cubic 的时候, 就会因为丢包造成的「乘性减」导致速度暴死, 而多个 TCP 连接存在的时候就可以相对避免这种情况, 每个连接控制的速率都会比较低, 更容易稳定在最大带宽上. 当然如果固定丢包率高的话, 最好还是交给 BBR.

当然还有就是服务器端可能对每个 http session 的最大速率做了限制, 比方说早前百度云只允许一个免费用户创建一个连接, 然后速度又差不多是在 128KB/s, 通过 aria2c 就可以强行启动多线程下载, 这样即便每个连接都是 128KB/s, 你开了十几条线程, 速度就能获得很大提升.

类似的话题

本站所有内容均为互联网搜索引擎提供的公开搜索信息,本站不存储任何数据与内容,任何内容与数据均与本站无关,如有需要请联系相关搜索引擎包括但不限于百度google,bing,sogou

© 2025 tinynews.org All Rights Reserved. 百科问答小站 版权所有