本篇文章已授權微信公眾號 YYGeeker
獨家釋出轉載請標明出處
CSDN學院課程地址
- RxJava2從入門到精通-初級篇:edu.csdn.net/course/deta…
- RxJava2從入門到精通-中級篇:edu.csdn.net/course/deta…
- RxJava2從入門到精通-進階篇:edu.csdn.net/course/deta…
- RxJava2從入門到精通-原始碼分析篇:edu.csdn.net/course/deta…
5. RxJava背壓策略(BackpressureStrategy)
5.1 背壓是什麼
背壓的概念是在平時業務開發時較為常見,大多數是針對高併發的業務,背壓是必須考慮的因素之一。在非同步場景中,由於資料流的發射速度高於資料流的接收速度,就會導致資料不能及時處理,從而導致資料流的阻塞。背壓所要做的事情就是主動控制資料流發射的速度
在RxJava2.0中,推出了Flowable用來支援背壓,去除了Observable對背壓的支援,下面在背壓策略的講解中,我們都使用Flowable作為我們的響應型別。在使用背壓時,只需要在create()
方法中第二個引數新增背壓策略即可
- 在訂閱的時候如果使用
FlowableSubscriber
,那麼需要通過s.request(Long.MAX_VALUE)
去主動請求上游的資料項。如果遇到背壓報錯的時候,FlowableSubscriber
預設已經將錯誤try-catch,並通過onError()
進行回撥,程式並不會崩潰 - 在訂閱的時候如果使用
Consumer
,那麼不需要主動去請求上游資料,預設已經呼叫了s.request(Long.MAX_VALUE)
。如果遇到背壓報錯、且對Throwable的Consumer
沒有new出來,則程式直接崩潰 - 背壓策略的上游的預設快取池是128
public abstract class Flowable<T> implements Publisher<T> {
/** The default buffer size. */
static final int BUFFER_SIZE;
static {
BUFFER_SIZE = Math.max(1, Integer.getInteger("rx2.buffer-size", 128));
}
}
複製程式碼
5.2 MISSING
MISSING表示OnNext事件沒有任何快取和丟棄,下游要處理任何溢位,可以理解為相當於沒有指定背壓策略。Flowable相當於沒有指定背壓策略可以將下游要處理任何溢位理解為,上游發射的資料未得到處理,就會快取起來,當快取容量達到128時,再增加一個未處理的資料項,就會丟擲MissingBackpressureException,且帶有佇列已經滿了的友好提示。這裡就好比一個大水缸,當水注滿的時候,它就會把蓋子蓋上,不讓你再繼續注水了
這裡我們模擬上游傳送速度高於下游資料流的處理速度,在資料處理的時候加上
Thread.sleep(1000)
public void missing() {
Flowable.create(new FlowableOnSubscribe<Integer>() {
@Override
public void subscribe(FlowableEmitter<Integer> emitter) throws Exception {
for (int i = 0; i < 129; i++) {
emitter.onNext(i);
}
}
}, BackpressureStrategy.MISSING)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new FlowableSubscriber<Integer>() {
@Override
public void onSubscribe(Subscription s) {
s.request(Long.MAX_VALUE);
}
@Override
public void onNext(Integer integer) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.e("TAG", "onNext=" + integer);
}
@Override
public void onError(Throwable t) {
t.printStackTrace();
}
@Override
public void onComplete() {
}
});
}
複製程式碼
輸出
io.reactivex.exceptions.MissingBackpressureException: Queue is full?!
複製程式碼
5.3 ERROR
ERROR表示在下游無法跟上時,會丟擲MissingBackpressureException。可以將下游無法跟上理解為,上游發射的資料未得到處理,就會快取起來,當快取容量達到128時,再增加一個未處理的資料項,就會丟擲MissingBackpressureException。這裡好比一個大水缸,當水注滿的時候,它會把水缸撐破了,直接破裂
public void error() {
Flowable.create(new FlowableOnSubscribe<Integer>() {
@Override
public void subscribe(FlowableEmitter<Integer> emitter) throws Exception {
for (int i = 0; i < 129; i++) {
emitter.onNext(i);
}
}
}, BackpressureStrategy.ERROR)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new FlowableSubscriber<Integer>() {
@Override
public void onSubscribe(Subscription s) {
s.request(Long.MAX_VALUE);
}
@Override
public void onNext(Integer integer) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.e("TAG", "onNext=" + integer);
}
@Override
public void onError(Throwable t) {
t.printStackTrace();
}
@Override
public void onComplete() {
}
});
}
複製程式碼
輸出
io.reactivex.exceptions.MissingBackpressureException: create: could not emit value due to lack of requests
複製程式碼
5.4 BUFFER
上游不斷的發出onNext請求,直到下游處理完,上游發射的資料項的快取池是無限大的,程式也不會丟擲錯誤,但是要注意程式OOM的現象,因為快取越大,佔用的記憶體就越多。例子中發射129個資料項,然而程式並沒有崩潰,只會一直讀取快取池的資料項,直到資料項被處理完。這裡就是一個無限大的水缸
背壓策略除了BUFFER策略的快取池是無限大之外,其他預設的快取池都是128
public void buffer() {
Flowable.create(new FlowableOnSubscribe<Integer>() {
@Override
public void subscribe(FlowableEmitter<Integer> emitter) throws Exception {
for (int i = 0; i < 1000; i++) {
emitter.onNext(i);
}
}
}, BackpressureStrategy.BUFFER)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new FlowableSubscriber<Integer>() {
@Override
public void onSubscribe(Subscription s) {
s.request(Long.MAX_VALUE);
}
@Override
public void onNext(Integer integer) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.e("TAG", "onNext=" + integer);
}
@Override
public void onError(Throwable t) {
t.printStackTrace();
}
@Override
public void onComplete() {
}
});
}
複製程式碼
輸出
onNext=0
onNext=1
onNext=2
......
onNext=998
onNext=999
複製程式碼
5.5 DROP
會在下游跟不上速度時,把onNext的值丟棄,簡單的說就是,超過快取區大小(128)的資料項都會被丟棄。例子中通過發射800個資料項,那麼我們只會收到0-127的資料項。如果我們再次呼叫request()
,這時候取到的資料就是上一次request()後的128個資料。這裡好比一個大水缸,當水注滿的時候,水還是在繼續的流,一旦有request呼叫的時候,它就會去取出水缸裡的所有水,這時候水缸就是空的,但水一直在流,所以水缸馬上又會被注滿,這個時候就要等request再次取出水缸裡的水
public void drop() {
Flowable.create(new FlowableOnSubscribe<Integer>() {
@Override
public void subscribe(FlowableEmitter<Integer> emitter) throws Exception {
for (int i = 0; i < 1000; i++) {
emitter.onNext(i);
}
}
}, BackpressureStrategy.DROP)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new FlowableSubscriber<Integer>() {
@Override
public void onSubscribe(Subscription s) {
s.request(Long.MAX_VALUE);
}
@Override
public void onNext(Integer integer) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.e("TAG", "onNext=" + integer);
}
@Override
public void onError(Throwable t) {
t.printStackTrace();
}
@Override
public void onComplete() {
}
});
}
複製程式碼
輸出
onNext=0
onNext=1
onNext=2
......
onNext=127
複製程式碼
5.6 LATEST
LATEST與Drop策略一樣,如果超過快取池容量大小的資料項都會被丟棄。不同的是,不管快取池的狀態如何,LATEST都會將最後一條資料強行放入快取池中。這裡的水缸容納下了最後一滴水
public void latest() {
Flowable.create(new FlowableOnSubscribe<Integer>() {
@Override
public void subscribe(FlowableEmitter<Integer> emitter) throws Exception {
for (int i = 0; i < 1000; i++) {
emitter.onNext(i);
}
}
}, BackpressureStrategy.LATEST)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new FlowableSubscriber<Integer>() {
@Override
public void onSubscribe(Subscription s) {
s.request(Long.MAX_VALUE);
}
@Override
public void onNext(Integer integer) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.e("TAG", "onNext=" + integer);
}
@Override
public void onError(Throwable t) {
t.printStackTrace();
}
@Override
public void onComplete() {
}
});
}
複製程式碼
輸出
onNext=0
onNext=1
......
onNext=126
onNext=127
onNext=999
複製程式碼
5.7 小結
- MISSING:沒有任何快取和丟棄,下游要處理任何溢位
- ERROR:下游的處理速度無法跟上上游的發射速度時報錯
- BUFFER:資料項的快取池無限大
- DROP:下游的處理速度無法跟上上游的發射速度時丟棄
- LATEST:最後一條資料項被強行放入快取池