日常工作中,大家应该经常遇到要下载资源的场景,下载资源时,有时网络很给力,一会儿就下载成功了,有时下载很慢,几十分钟后都还在下载中,甚至更过分的是下载好长时间后直接来个下载失败。好不惹人生气。 当你在遇到这样的下载场景时,有没有思考过到底是什么原因影响着文件资源的下载速度呢?
决定用户下载大文件速度快慢的终极因素,在于用户下载进程实时抢占网络带宽的大小。其它的因素与它相比,可以忽略不计。
如果用户进程实时抢占的带宽 = 实时网络可用带宽,则在最理想的状态下,用户下载进程100%利用网络带宽,无论该下载进程是单线程(Thread)的还是多线程的,下载速度几乎没有任何区别。【因为此时没有别的进程使用网络带宽】。
但是在现实中实际是用户进程实时抢占的带宽 <= 实时网络可用带宽!因为实时网络带宽每一刻都是在变化的,那它是怎么变化的呢?因为TCP流量控制。
传统的TCP流量探测机制有一个非常致命的缺陷:一旦检测到有丢包,立马将发送速率降为1/2。降速1/2后,如果没有丢包,将会在1/2速率的基础上,按照固定的增长值(线性增长),加大发送的速率。接下来就会一直按照这个节奏到达丢包的那一刻(实时可用带宽)为止。如果下一个检测周期依然有丢包现象,会在当前1/2速率的基础上继续降速1/2。循环往复,直到文件下载结束。
很显然指数级的降速、但是线性的增速;这最后造成的结果就是真实的传输速率远远小于实时可用带宽。
多线程下载时,由于多个线程在竞争实时可用带宽。尽管多线程逻辑上是并行的,但其实还是按时序的串行处理。所以每个线程处于的阶段并不一致。并且带宽资源是固定的。
比如使用3个线程来进行下载,因为处于不同的阶段,有的线程因为丢包直接降速1/2,有的线程处于线性增长阶段。通过多个线程的加权平均,最后得到的下载曲线是一条平滑的曲线,且这条曲线大多数应该处于单线程下载速率的上方。这也是为什么多线程下载大文件的速度更快的原因了。
最后,如果我问你写一个程序来求1亿以内素数个数,在求素数的算法已经确定的情况下,用什么样的方式花的时间更少呢?我想答案应该很清楚吧。
end