溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

iOS編程學(xué)習(xí)中關(guān)于throttle的那些事

發(fā)布時(shí)間:2020-09-10 10:17:34 來(lái)源:腳本之家 閱讀:202 作者:MrPeak 欄目:移動(dòng)開發(fā)

前言

不知道大家對(duì)throttle這個(gè)單詞是否看著眼熟,還是說(shuō)對(duì)這個(gè)計(jì)算機(jī)基礎(chǔ)概念有很清晰的了解了。今天就來(lái)聊聊和throttle相關(guān)的一些技術(shù)場(chǎng)景。

定義

我經(jīng)常有一種感覺,對(duì)于英語(yǔ)這門語(yǔ)言的語(yǔ)感,會(huì)影響我們對(duì)于一些關(guān)鍵技術(shù)概念的理解。有時(shí)候在學(xué)習(xí)新技術(shù)知識(shí)的時(shí)候,我會(huì)先花一些時(shí)間去了解術(shù)語(yǔ)英文單詞的各種語(yǔ)義,在形成強(qiáng)烈清晰的語(yǔ)感之后,再去深入具體的技術(shù)語(yǔ)境。throttle也算是個(gè)生僻的單詞,至少在口語(yǔ)中畢竟少用到,先來(lái)看看詞義:

a device controlling the flow of fuel or power to an engine.

中文翻譯是節(jié)流器,一種控制流量的設(shè)備。對(duì)應(yīng)到我們計(jì)算機(jī)世界,可以理解成,一種控制數(shù)據(jù)或者事件流量大小的機(jī)制。這么說(shuō)可能還是有些抽象,再來(lái)看看一些具體的技術(shù)場(chǎng)景加深理解。

場(chǎng)景一:GCD Background Queue

話說(shuō)GCD幾乎是iOS面試的必問(wèn)題,也是個(gè)送分題:)。

我一般會(huì)機(jī)械式的先問(wèn):GCD有哪幾種Queue?回答:串行Queue和并行Queue。

我繼續(xù)問(wèn):Global Queue有哪幾種優(yōu)先級(jí)?回答:有幾種吧,大概記得Default,Low,High吧。

我雙眉一挑,進(jìn)一步試探:不知道少俠有沒(méi)有研究過(guò)DISPATCH_QUEUE_PRIORITY_BACKGROUND作何用?問(wèn)完立即豎起耳朵,殷殷期盼縈繞于心的關(guān)鍵字。如果能聽到「I/O Throttle 呀!」,我會(huì)瞬間覺得面試氣氛被點(diǎn)亮了。

當(dāng)然啦,答不出I/O Throttle并不能說(shuō)明技術(shù)不扎實(shí),但能答出來(lái),至少表明對(duì)待技術(shù)是有好奇心的,加分!

官方文檔如是說(shuō):

Items dispatched to the queue run at background priority; the queue is scheduled for execution after all high priority queues have been scheduled and the system runs items on a thread whose priority is set for background status. Such a thread has the lowest priority and any disk I/O is throttled to minimize the impact on the system.

那Disk I/O Throttle做什么用呢?按照上面這段描述,Disk I/O會(huì)impact system performance。

理解Disk I/O的影響需要補(bǔ)充一些大學(xué)課本上的知識(shí)。一次磁盤讀寫操作涉及到的硬件資源主要有兩個(gè),CPU和磁盤。任務(wù)本身由CPU觸發(fā)和調(diào)度,讀操作發(fā)生時(shí),CPU告知Disk去獲取某個(gè)地址的數(shù)據(jù),此時(shí)由于Disk的讀操作存在尋址延遲,CPU是處于I/O wait狀態(tài),一直維持到Disk返回?cái)?shù)據(jù)為止。處于I/O wait狀態(tài)的CPU,此時(shí)并不能把這部分等待的時(shí)間用來(lái)處理其他任務(wù),也就是說(shuō)這一段等待的CPU時(shí)間被“浪費(fèi)”了。而CPU是公共的系統(tǒng)資源,這部分資源的損耗自然會(huì)對(duì)系統(tǒng)的整體表現(xiàn)產(chǎn)生負(fù)面影響。即使Global Queue使用的是子線程,也會(huì)造成CPU資源的消耗。

如果把任務(wù)的Priority調(diào)整為DISPATCH_QUEUE_PRIORITY_BACKGROUND,那么這些任務(wù)中的I/O操作就被被控制,雖然具體的控制策略并沒(méi)有官方文檔描述(一種可能的策略是并發(fā)的Disk I/O變?yōu)榇械模?,但我們能確認(rèn)的是,部分I/O操作的啟動(dòng)時(shí)間很有可能被適當(dāng)延遲,把更多的CPU資源騰出來(lái)處理其他任務(wù)(比如說(shuō)一些系統(tǒng)資源的調(diào)度任務(wù)),這樣可以讓我們的系統(tǒng)更加穩(wěn)定高效。簡(jiǎn)而言之,對(duì)于重度磁盤I/O依賴的后臺(tái)任務(wù),如果對(duì)實(shí)時(shí)性要求不高,放到DISPATCH_QUEUE_PRIORITY_BACKGROUND Queue中是個(gè)好習(xí)慣,對(duì)系統(tǒng)更友好。

實(shí)際上I/O Throttle還分為好幾種,有Disk I/O Throttle,Memory I/O Throttle,和Network I/O Throttle。語(yǔ)義類似只不過(guò)場(chǎng)景不同,繼續(xù)往下看。

場(chǎng)景二:ASIHttpRequest Network Throttle

早幾年讀ASIHttpRequest源碼的時(shí)候,讀到過(guò)一段有意思的代碼:

- (void)handleNetworkEvent:(CFStreamEventType)type
{
//...
 [self performThrottling];
//...
}

在AFNetworking中也有類似的代碼:

/**
 Throttles request bandwidth by limiting the packet size and adding a delay for each chunk read from the upload stream.
 
 When uploading over a 3G or EDGE connection, requests may fail with "request body stream exhausted". Setting a maximum packet size and delay according to the recommended values (`kAFUploadStream3GSuggestedPacketSize` and `kAFUploadStream3GSuggestedDelay`) lowers the risk of the input stream exceeding its allocated bandwidth. Unfortunately, there is no definite way to distinguish between a 3G, EDGE, or LTE connection over `NSURLConnection`. As such, it is not recommended that you throttle bandwidth based solely on network reachability. Instead, you should consider checking for the "request body stream exhausted" in a failure block, and then retrying the request with throttled bandwidth.
 
 @param numberOfBytes Maximum packet size, in number of bytes. The default packet size for an input stream is 16kb.
 @param delay Duration of delay each time a packet is read. By default, no delay is set.
 */
- (void)throttleBandwidthWithPacketSize:(NSUInteger)numberOfBytes
         delay:(NSTimeInterval)delay;

原諒我貼了一大段注釋,這段英文描述對(duì)于加深我們對(duì)于一些網(wǎng)絡(luò)行為的理解很有幫助。

這些知名的第三方網(wǎng)絡(luò)框架都有對(duì)Newtork Throttle的支持,你可能會(huì)好奇,我們?yōu)槭裁匆獙?duì)自己發(fā)出的網(wǎng)絡(luò)請(qǐng)求做流量控制,難道不應(yīng)該盡可能最大限度的利用帶寬嗎?

此處需要科普一點(diǎn)TCP協(xié)議相關(guān)的知識(shí)。我們通過(guò)HTTP請(qǐng)求發(fā)送數(shù)據(jù)的時(shí)候,實(shí)際上數(shù)據(jù)是以Packet的形式存在于一個(gè)Send Buffer中的,應(yīng)用層平時(shí)感知不到這個(gè)Buffer的存在。TCP提供可靠的傳輸,在弱網(wǎng)環(huán)境下,一個(gè)Packet一次傳輸失敗的概率會(huì)升高,即使一次失敗,TCP并不會(huì)馬上認(rèn)為請(qǐng)求失敗了,而是會(huì)繼續(xù)重試一段時(shí)間,同時(shí)TCP還保證Packet的有序傳輸,意味著前面的Packet如果不被ack,后面的Packet就會(huì)繼續(xù)等待,如果我們一次往Send Buffer中寫入大量的數(shù)據(jù),那么在弱網(wǎng)環(huán)境下,排在后面的Packet失敗的概率會(huì)變高,也就意味著我們HTTP請(qǐng)求失敗的幾率會(huì)變大,類似這樣:

iOS編程學(xué)習(xí)中關(guān)于throttle的那些事

大部分時(shí)候在應(yīng)用層寫代碼的時(shí)候,估計(jì)不少同學(xué)都意識(shí)不到Newtork Throttle這種機(jī)制的存在,在弱網(wǎng)環(huán)境下(丟包率高,帶寬低,延遲高)一些HTTP請(qǐng)求(比如上傳圖片或者日志文件)失敗率會(huì)激增,有些朋友會(huì)覺得這個(gè)我們也沒(méi)辦法,畢竟網(wǎng)絡(luò)辣么差。其實(shí),作為有追求的工程師,我們可以多做一點(diǎn)點(diǎn),而且弱網(wǎng)下請(qǐng)求的成功率其實(shí)是個(gè)很值得深入研究的方向。針對(duì)弱網(wǎng)場(chǎng)景,我們可以啟用Newtork Throttle機(jī)制,減小我們一次往Send Buffer中寫入的數(shù)據(jù)量,或者延遲某些請(qǐng)求的發(fā)送時(shí)間,這樣所有的請(qǐng)求在弱網(wǎng)環(huán)境下,都能「耐心一點(diǎn),多等一會(huì)」,請(qǐng)求成功率自然也就適當(dāng)提高啦。

那么,再看AFNetworking中的這個(gè)函數(shù),是不是更能理解了呢?

- (void)throttleBandwidthWithPacketSize:(NSUInteger)numberOfBytes
         delay:(NSTimeInterval)delay;

Network Throttle體現(xiàn)了一句至理名言「慢即是快」。

場(chǎng)景三:Event Frequency Control

不知道大家在寫UI的時(shí)候,有沒(méi)有遇到過(guò)用戶快速連續(xù)點(diǎn)擊UIButton,產(chǎn)生多次Touch事件回調(diào)的場(chǎng)景。以前機(jī)器還沒(méi)那么快的時(shí)候,我在用一些App的時(shí)候,時(shí)不時(shí)會(huì)遇到偶爾卡頓,多次點(diǎn)擊一個(gè)Button,重復(fù)Push同一個(gè)Controller。有些工程師會(huì)在Button的點(diǎn)擊事件里記錄一個(gè)timestamp,然后判斷每次點(diǎn)擊的時(shí)間間隔,間隔過(guò)短就忽略,這也不失為一種解決辦法。

再后來(lái)學(xué)習(xí)RxSwift的時(shí)候,看到:

button.rx_tap
 .throttle(0.5, MainScheduler.instance)
 .subscribeNext { _ in 
  print("Hello World")
 }
 .addDisposableTo(disposeBag)

終于有了優(yōu)雅的書寫方式。發(fā)現(xiàn)沒(méi)有,throttle又出現(xiàn)了,這里throttle控制的是什么呢?不是disk讀寫,也不是network buffer,而是事件,把事件本身抽象成了一種Data,控制這種數(shù)據(jù)的流量或者產(chǎn)生頻率,就解決了上面我們所說(shuō)重復(fù)點(diǎn)擊按鈕的問(wèn)題,so easy。

總結(jié)

當(dāng)然還會(huì)有更多的場(chǎng)景,throttle其實(shí)是個(gè)基礎(chǔ)的計(jì)算機(jī)知識(shí)。理解throttle相關(guān)的技術(shù)概念,需要在不同場(chǎng)景下去抽象出一個(gè)flow被節(jié)流的畫面?,F(xiàn)在,如果讓你來(lái)解釋一些具體的技術(shù)場(chǎng)景下,throttle是怎么回事,是不是可以信手拈來(lái)了:)

好了,以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)億速云的支持。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI