为什么要多线程下载
俗话说要以终为始,那么我们首先要明确多线程下载的目标是什么,不外乎是为了更快的下载文件。那么问题来了,多线程下载文件相比于单线程是不是更快?
对于这个问题可以看下图。
横坐标是线程数,纵坐标是使用对应线程数下载对应文件时花费的时间,蓝橙绿代表下载文件的大小,每个线程下载对应文件20次,根据对应数据绘制了上图。
可以看出在忽略个别网络波动出现的突出点后,整体的趋势是线程数量的提升对下载速度没有多大影响。根据上述图片可以得出的结论是,单线程下载就够了,还需要多线程下载干嘛?既没有提升还增加麻烦。
根据目前测试结果来看这个结论是没有问题的。那我们试着在分析下问题,想一想此时为什么多线程下载没有作用?可以看下橙色线条下载文件为55M左右,下载时间平均在5s左右,平均下载速度大概为11M左右,还有绿色线条文件大概224M,下载速度平均为20s,平均下载速度大概在11M左右。而我本地网络是100M宽带,实际下行速率的上限是12.5M,可以看出下载速度已经逼近下行峰值。此时无论是单个线程还是多个线程都可以将下载带宽跑满,那么即使是开多个线程也不能把本地带宽提高,你也不能把本地100M带宽变成300M,所以这里使用多线程进行下载速度基本不可能提升了,除非我换宽带加到300M或更大。这里可以看出是本地带宽限制了下载速度。
由此我们可以得出结论,下载速度由本地带宽决定,本地带宽已经跑满的情况下,下载速度无法进行提升,这个也比较符合我们的正常逻辑,网速不够怎么办,换更大的带宽,速度自然提升,当然也意味着交更多的钱....。
那么问题真的是如此吗,比如我们知道的某网盘,管你本地带宽多大,我都只有几十或几百k的下载速度。你强任你强,你能跑满带宽算我输!!!当然开VIP还是可以享受加速服务的,加速二字划重点。
此时可以看出是服务器端限制了下载速度,即使我本地有很大带宽但依然跑不满。那么这个时候我上多线程会有提升吗?可以看下图。
这是一个下载文件限速的网址,使用不同线程数进行下载,根据线程数和下载花费时间绘制的图片。可以看到随着线程数的增加,下载速度显著提升,一个线程情况下55M文件下载了550s左右,平均速度为100k每秒,100个线程下载大概需要6秒,平均速度大概为9M每秒,加上线程创建请求等开销基本逼近本地带宽上限。
由上述可知,在服务器不限速或者说服务器的传输速度大于等于本地带宽的情况下,单线程下载足矣。在服务器对单个连接下载限速时,使用多线程可以提升下载速度。但服务器本身的带宽也是有限的,例如服务器带宽为300M,下载速度可达37.5M/s.这时有多个用户在进行下载,此时可能开了多线程也不会有太大收益,服务器本身带宽已经很紧张了,你也不能无中生有,突破带宽本身的上限。就有点像抢票软件,资源没那么紧张的使用抢票软件有一定提升可以方便抢到,等到春运时即使用抢票软件抢,也很难抢到票。
前置条件
上述说明了在什么时候可以快的问题。可以看出在特定情况下还是有收益的,既然有收益,那么就值得我们去做。既然要做那么就面临第一个问题,能不能做?怎么做是第二步,第一步首先要考虑能不能做的问题,违法的事情当然不能做,受客观条件限制目前做不了的事也不能做。
那么首先可以想一想多线程下载的大概思路,一个线程下载一部分,然后将所有下载好的内容组装再一次。比如一个文件有2kb(2048byte),一共两个线程下载,第一个线程下载第一个1kb,第二个线程下载第二个1kb,然后将第一个下载好的1kb写入文件,接着将下载好的第二个1kb写入文件,下载完成。
实现上述流程,向服务器请求时,服务器必须能返回下载文件指定范围的数据。也就是说服务器需要支持http请求中的关键字Range
.Range
的常规格式为Range : bytes=start-end
其中start表示起始字节