做者:張鐵蕾
連接:https://www.zhihu.com/question/49618581/answer/117107570
來源:知乎
著做權歸做者全部,轉載請聯繫做者得到受權。
首先,從大的方面說,這篇文檔的名字,雖然叫「Backpressure」(背壓),但倒是在講述一個更大的話題,「Flow Control」(流控)。Backpressure只是解決Flow Control的其中一個方案。 就像小學作的那道數學題:一個水池,有一個進水管和一個出水管。若是進水管水流更大,過一段時間水池就會滿(溢出)。這就是沒有Flow Control致使的結果。 而解決Flow Control有幾種思路呢? (1)Backpressure,就是消費者須要多少,生產者就生產多少。這有點相似於TCP裏的流量控制,接收方根據本身的接收窗口的狀況來控制接收速率,並經過反向的ACK包來控制發送方的發送速率。這種方案只對於cold Observable有效。cold Observable是那些容許下降速率的發送源,好比兩臺機器傳一個文件,速率可大可小,即便下降到每秒幾個字節,只要時間足夠長,仍是可以完成的。相反的例子就是音視頻直播,速率低於某個值整個功能就無法用了(這種相似於hot Observable)。 (2)節流(Throttling),說白了就是丟棄。消費不過來,就處理其中一部分,剩下的丟棄。至於處理哪些和丟棄哪些,就有不一樣的策略,也就是sample (or throttleLast)、throttleFirst、debounce (or throttleWithTimeout)這三種。仍是舉音視頻直播的例子,在下游處理不過來的時候,就須要丟棄數據包。 (3)打包(buffer和window)。buffer和window基本同樣,只是輸出格式不太同樣。它們是把上游多個小包裹打成大包裹,分發到下游。這樣下游須要處理的包裹的個數就減小了。 (4)是一種特殊狀況,阻塞住整個調用鏈(Callstack blocking)。之因此說這是一種特殊狀況,是由於這種方式只適用於整個調用鏈都在一個線程上同步執行,這要求中間的各個operator都不能啓動新的線程。在日常使用中這種應該是比較少見的,由於咱們常用subscribeOn或observeOn來切換執行線程,並且有些複雜的operator自己也會內部啓動新的線程來處理。另外,若是真的出現了徹底同步的調用鏈,前面的(1)(2)(3)仍然有可能適用的,只不過這種阻塞的方式更簡單,不須要額外的支持。 舉個例子比較一下(1)和(4)。(4)至關於不少車行駛在盤山公路上,而公路只有一條車道。那麼排在最前面的第一輛車就擋住了整條路,後面的車也只能排在後面。而(1)至關於銀行辦業務時的窗口叫號,窗口主動叫某個號過去(至關於請求),那我的纔過去辦理。 而後,從細的方面解釋一下sample,throttleFirst,debounce。以及onBackpressureBuffer,onBackpressureDrop,onBackpressureBlock和ConnectableObservable(multicast)。 sample就是throttleLast,採樣。類比一下音頻採樣,8kHz的音頻就是每125微秒採一個值。sample能夠配置成,好比每100毫秒採樣一個值,但100毫秒內上游可能過來不少值,選那個值呢,就是選最後那個值。因此它也叫throttleLast。 throttleFirst跟sample相似,好比仍是每100毫秒採樣一個值,但選這100毫秒內的第一個值。 debounce,也叫throttleWithTimeout,名字裏就包含一個例子。好比,一個網絡程序維護一個TCP鏈接,不停地收發數據,但中間沒數據能夠收發的時候,就有間歇。這段間歇的時間,能夠稱爲idle time。當idle time超過一個預設值的時候,就算超時了(timeout),這個時候可能就須要把鏈接斷開了。實際上一些作server端的網絡程序就是這麼工做的。每收發一個數據包以後,啓動一個計時器,等待idle time過去以後的超時,若是計時器到時以前,又有收發數據包的行爲,那麼計時器重置,等待一個新的idle time。當計時器到時了,就time out了,這個鏈接就能夠關閉了。debounce的行爲,跟這個很是相似,能夠用它來找到連續的收發事件以後idle time超時後的timeout事件。 最後還有一個新的問題須要說明。Backpressure有些Observable是支持的,有些不支持。但它們能夠經過operator來轉化。 onBackpressureBuffer,onBackpressureDrop,onBackpressureBlock就能夠把一個不支持Backpressure的Observable轉成一個支持Backpressure的Observable(即支持request請求)。但轉完以後的策略不太相同。 onBackpressureBuffer是不丟棄數據的處理方式。把上游收到的所有緩存下來,等下游來請求再發給下游。至關於一個水庫。但上游太快,就會buffer溢出。 onBackpressureDrop就是當上游來數據的時候,看下游有沒有需求,有需求就發給下游,不然上游來的數據就丟掉。 onBackpressureBlock也是看下游有沒有需求,下游沒有需求,不丟棄,但試圖堵住上游的入口(能不能真堵得住還得看上游的狀況了),本身並不緩存。 相反,有時候一些operator也能把一個支持Backpressure的Observable變成一個不支持Backpressure的Observable。好比,ConnectableObservable就是這樣。它相似於把一條河的主幹,在下游分紅若干支流(但不太同樣的是每條支流的水量都跟主幹同樣,是拷貝的)。那麼很好理解,下游某個支流想對上游產生背壓,是不太可能的,它阻止不了水流流向其它支流。