一、為什么要使用多線程脉漏,多線程真的能提高效率嗎?
- 1.1為什么要使用多線程
多線程編程的目的切距,就是"最大限度地利用CPU資源",當某一線程的處理不需要占用CPU而只和I/O等資源打交道時惨远,讓需要占用CPU資源的其它線程有機會獲得CPU資源谜悟。從根本上說,這就是多線程編程的最終目的北秽。
因為單線程只會映射到一個CPU上葡幸,而多線程會映射到多個CPU上,多線程技術(shù)本質(zhì)是多線程硬件化贺氓,所以也會加快程序的執(zhí)行速度∥颠叮現(xiàn)在的PC或者手機有很多都是多核的,如果只使用單一的線程去處理任務,資源得不到充分利用辙培。
- 1.2多線程能提高效率嗎
打個比方,比如修一個橋洞蔑水,有2種開工方法
方案一、只在橋的一頭挖扬蕊,直至挖到橋的另一頭搀别,從而打通橋洞,這可以看成是單線程尾抑。
方案二歇父、在橋的兩頭挖,同時開工再愈,最后在橋的中間接通榜苫,從而打通橋動,這感覺肯定比方案一快了很多翎冲,好比多線程单刁。
假設(shè)每挖5分鐘,就需要清理一下挖出來的泥土府适。有一個小車在清理它們,工人只有一個肺樟。
單線程的做法是: 挖5分鐘檐春。然后工人停止挖,小車清理石土的5分鐘里么伯,工人在等待疟暖。
2個線程的做發(fā)是: 挖5分鐘,小車來清理泥土。這5分鐘里俐巴,工人在另一頭挖骨望。
這個比喻至少能說明點問題:小車清理泥土,就相當于磁盤io等相對于cpu計算來說比較慢的操作欣舵。在cpu空閑的時候可以讓其去做其它事情擎鸠,達到充分利用的效果。
- 1.3線程越多越好缘圈?
并不是線程越多性能越好劣光,當線程超過一定數(shù)量的時候,線程的調(diào)度將會變成很大的開銷糟把,反而會讓性能降低绢涡,所以要適當使用多線程,不能濫用遣疯。二者不是線性關(guān)系雄可。
計算機中一般來說只有一個CPU,也就是說只有一個工人〔現(xiàn)在把修橋方案變動一下数苫。
方案一:只在山的一頭挖,直至挖到山的另一頭夭坪,從而打通隧道戈二,這可以看成是單線程立莉。
方案二:在山的兩頭挖,同時開工,最后在山的中間接通诽里,從而打通隧道,這感覺肯定比1快了很多丑勤,好比多線程稳强。
方案二雖然是在山的兩頭開挖,但是由于工作的人只有一個间涵,所以只有讓這個人在山的兩頭跑仁热,挖一會這頭再去挖另一頭,來回跑是要花費額外時間的(好比線程的切換和調(diào)度)勾哩。
再舉二個例子:
例子一:
A單核單處理器,開一個線程跑循環(huán)輸出10萬條打印信息
B開100個線程輸出10萬條打印信息抗蠢。
后者比前者慢,因為輸出端是臨界資源(臨界資源:多道程序系統(tǒng)中存在許多進程,它們共享各種資源思劳,然而有很多資源一次只能供一個進程使用迅矛。一次僅允許一個進程使用的資源稱為臨界資源。許多物理設(shè)備都屬于臨界資源潜叛,如輸入機秽褒、打印機壶硅、磁帶機等。),線程搶占的時間大,單線程則無需搶占销斟。
例子二:
A網(wǎng)絡(luò)服務器處理,每個請求開一個線程,請求的處理時間極短,迅速返回庐椒。
B一次提交10萬個請求,則有10萬次線程創(chuàng)建和銷毀對應于一個工作線程處理這10萬條。請求后者比前者肯定快蚂踊。
二约谈、為什么要使用斷點續(xù)傳
在進行數(shù)據(jù)上傳的時候可能是多線程操作,很多圖像數(shù)據(jù)同時做上傳或者單一的圖像悴势,如果圖像比較多或者單一圖像數(shù)據(jù)比較大窗宇,自然不希望失敗一次或者暫停一次之后完全重傳,有斷點續(xù)傳功能可以節(jié)省網(wǎng)絡(luò)流量和節(jié)省用戶時間特纤,體驗自然比你一次次的重傳好很多军俊。
三、Java斷點續(xù)傳原理
3.1什么是斷點續(xù)傳
所謂斷點續(xù)傳捧存,也就是要從文件已經(jīng)下載的地方開始繼續(xù)下載粪躬。在以前版本的 HTTP 協(xié)議是不支持斷點的,HTTP/1.1 開始就支持了昔穴。一般斷點下載時才用到 Range 和 Content-Range 實體頭镰官。下面會介紹HTTP版本的發(fā)展歷程。
3.2什么是Range吗货?
當用戶在聽一首歌的時候泳唠,如果聽到一半(網(wǎng)絡(luò)下載了一半),網(wǎng)絡(luò)斷掉了宙搬,用戶需要繼續(xù)聽的時候笨腥,文件服務器不支持斷點的話,則用戶需要重新下載這個文件勇垛。而Range支持的話脖母,客戶端應該記錄了之前已經(jīng)讀取的文件范圍,網(wǎng)絡(luò)恢復之后闲孤,則向服務器發(fā)送讀取剩余Range的請求谆级,服務端只需要發(fā)送客戶端請求的那部分內(nèi)容,而不用整個文件發(fā)送回客戶端讼积,以此節(jié)省網(wǎng)絡(luò)帶寬肥照。
3.3HTTP1.1規(guī)范的Range是怎樣一個約定?
如果Server支持Range勤众,首先就要告訴客戶端建峭,咱支持Range,之后客戶端才可能發(fā)起帶Range的請求决摧。這里套用唐僧的一句話,你不說我怎么知道呢。response.setHeader('Accept-Ranges', 'bytes');
Server通過請求頭中的Range: bytes=0-xxx來判斷是否是做Range請求掌桩,如果這個值存在而且有效边锁,則只發(fā)回請求的那部分文件內(nèi)容,響應的狀態(tài)碼變成206波岛,表示Partial Content茅坛,并設(shè)置Content-Range。如果無效则拷,則返回416狀態(tài)碼贡蓖,表明Request Range Not Satisfiable。如果不包含Range的請求頭煌茬,則繼續(xù)通過常規(guī)的方式響應斥铺。
3.4應用場景
假設(shè)你要開發(fā)一個多線程下載工具,你會自然的想到把文件分割成多個部分坛善,比如4個部分晾蜘,然后創(chuàng)建4個線程,每個線程負責下載一個部分眠屎,如果文件大小為403個byte剔交,那么你的分割方式可以為:0-99 (前100個字節(jié)),100-199(第二個100字節(jié))改衩,200-299(第三個100字節(jié))岖常,300-402(最后103個字節(jié))。
分割完成葫督,每個線程都明白自己的任務竭鞍,比如線程3的任務是負責下載200-299這部分文件,現(xiàn)在的問題是:線程3發(fā)送一個什么樣的請求報文候衍,才能夠保證只請求文件的200-299字節(jié)笼蛛,而不會干擾其他線程的任務。這時蛉鹿,我們可以使用HTTP1.1的Range頭滨砍。
Range頭域可以請求實體的一個或者多個子范圍,Range的值為0表示第一個字節(jié)妖异,也就是Range計算字節(jié)數(shù)是從0開始的:
表示頭500個字節(jié):Range: bytes=0-499
表示第二個500字節(jié):Range: bytes=500-999
表示最后500個字節(jié):Range: bytes=-500
表示500字節(jié)以后的范圍:Range: bytes=500-
第一個和最后一個字節(jié):Range: bytes=0-0,-1
同時指定幾個范圍:Range: bytes=500-600,601-999
所以惋戏,線程3發(fā)送的請求報文必須有這一行:
Range: bytes=200-299
服務器接收到線程3的請求報文,發(fā)現(xiàn)這是一個帶有Range頭的GET請求他膳,如果一切正常响逢,服務器的響應報文會有下面這行:
HTTP/1.1 206 OK
表示處理請求成功,響應報文還有這一行
Content-Range: bytes 200-299/403
斜杠后面的403表示文件的大小
3.5Http協(xié)議的發(fā)展歷程
HTTP協(xié)議到現(xiàn)在為止總共經(jīng)歷了3個版本的演化棕孙,第一個HTTP協(xié)議誕生于1989年3月舔亭。
xml屬性 | 描述 |
---|---|
HTTP/0.9 | 1991年 |
HTTP/1.0 | 1992-1996年 |
HTTP/1.1 | 1997-1999年 |
HTTP/2.0 | 2012-2014年 |
也就是HTTP/1.1 從1997-1999 年就應用了些膨,所以現(xiàn)在基本上是支持斷點續(xù)傳的。
3.6模擬Http請求插件推薦
最后推薦一個模擬http請求的插件:HttpRequester,可以模擬Get/Post請求等,還可以添加Headers,Parameters參數(shù),非常方便钦铺。
在上面“3.2什么是Range订雾?”已經(jīng)顯示了使用該插件進行Get請求的截圖。
傳送門:HttpRequester怎么安裝和使用
https://jingyan.baidu.com/article/7c6fb4280b6a4180642c900c.html矛洞。
本文公號地址,后續(xù)文章持續(xù)更新中,微信掃描下方二維碼免費關(guān)注!洼哎,點此查看全部最新文章
我的博客
我的簡書
我的GitHub,喜歡的話給個star吧