Objective
Everyone loved the Backpressure
coming.
In this section we will study in the future Backpressure
. I look forward to eating more melon masses have already sat, do not worry, we first to review the previous section Zip
.
Business
In the previous section we said that zip can be sent to a number of upstream events sent to the downstream, then you have not thought of a problem, if one of the 水管A
sending event is particularly fast, and another 水管B
sending event is particularly slow, it is possible that this situation, the rapid 水管A
has sent 1000 events, and the slow hair 水管B
only sent out, the combination of a 999 left after the event 水管A
, these events need to continue to wait for the 水管B
sending event out of the combination, so many of the events are put in where? There's always a place to keep it, right? Zip gave us each one of the water pipes 水缸
, to save these events, with easy-to-understand pictures to indicate is:
Zip2.png
As shown in, where the blue box is zip
for us 水缸
! It saves the events from each water pipe, waits for two tanks to have events, and then pulls out an event from the tank to combine, waiting when one of the tanks is empty.
Off-topic: Let's analyze the characteristics of this water tank. It is in order to save, advanced events first taken out, this feature is not very familiar with it? Yes, this is what we know the queue, the water tank in the zip inside the implementation is the queue, interested in the source can be viewed through the view.
OK, back to the point, is there a size limit for this tank? What if we keep going? Let's look at an example:
observable<integer> Observable1 = Observable.create (New Observableonsubscribe<integer> () {@OverridePublicvoidSubscribe(observableemitter<integer> emitter)Throws Exception {for (int i =0;; i++) {Infinite cyclic hair event emitter.onnext (i); }}). Subscribeon (Schedulers.io ()); observable<string> observable2 = Observable.create (New Observableonsubscribe<string> () {@OverridePublicvoidSubscribe(observableemitter<string> emitter)Throws Exception {Emitter.onnext ("A"); }}). Subscribeon (Schedulers.io ()); Observable.zip (Observable1, Observable2,New Bifunction<integer, String, string> () {@OverridePublic StringApply (integer integer, String s) throws Exception {return integer + S; }}). Observeon (Androidschedulers.mainthread ()). Subscribe (new consumer<string> () { @Override public void accept (String s) throws Exception {log.d (TAG, s);}, new consumer<throwable > () { @Override public void accept (throwable Throwable) throws Exception {log.w (TAG, throwable);});
In this example, we created two water pipes, the first water pipe with the execution speed of the machine instructions to send an infinite loop of events, the second pipe randomly send something, because we did not send Complete
events, so the first water pipe will always send events to its corresponding tank, we come to see what the results of the operation.
Run the result GIF graph:
Zip2.gif
I took a grass, the memory occupied with a slope of 1 straight line up quickly, a few seconds more than 300 m, finally reported Oom:
zlc.season.rxjava2demo w/art:throwing outofmemoryerror " Failed to allocate a (byte allocation with4194304 free bytes and 8MB until OOM; Zlc.season.rxjava2demo w/art: "Main" prio=5 tid=1 Runnable zlc.season.rxjava2demo w/art: | group= "Main" scount=0 dscount=0 obj=0x75188710 self=0x7fc0efe7ba00 Zlc.season.rxjava2demo W/art: | systid=32686 nice=0 cgrp=default sched=0/0 handle=0x7fc0f37dc200 zlc.season.rxjava2demo W/art: | State=r schedstat= (0 0 0) utm=948 stm=120 core=1 hz=100 zlc.season.rxjava2demo W/art: | stack=0x7fff971e8000-0x7fff971ea000 stacksize=8mb Zlc.season.rxjava2demo W/art: | Held mutexes= "mutator lock" (shared held) Zlc.season.rxjava2demo W/art:at Java.lang.Inte Ger.valueof (integer.java:742)
This situation is definitely what we do not want to see, here can lead us Backpressure
, so-called in Backpressure
fact, in order to control the flow, tank storage capacity is limited, so we have 源头
to solve the problem, since you are so fast, the volume of data so large, Then I'll try not to let you go so fast.
So 源头
where exactly is this, when will this happen, here is just the zip example, where else will it appear? Take this question and let's explore.
Let's make things a little simpler from a single point of Observable
start.
Look at the snippet code:
Observable.create (New Observableonsubscribe<integer> () {@Overridepublic void subscribe (observableemitter<integer> emitter) throws Exception {for (int i = 0;; i++) {//Infinite Loop sends event emitter.onnext (i);}}). Subscribe (new consumer<integer> () { @Override public void Accept (integer integer) throws Exception {thread.sleep (2000); LOG.D (TAG,
This code is very simple, the upstream same infinite loop of the sending event, in the downstream each receive the event before the delay of 2 seconds. Upstream and downstream work in 同一个线程
, to see the results of the operation:
Peace.gif
Alas, how so calm, feel like to go the wrong piece of the field.
Why, because the upstream and downstream work in 同一个线程
Ah sao years! At this point, each call emitter.onNext(i)
is actually the equivalent of calling the consumer directly:
public void accept(Integer integer) throws Exception { Thread.sleep(2000); Log.d(TAG, "" + integer); }
So this time is actually upstream each time delay 2 seconds to send once. The final result also illustrates all this.
Let's add a thread, change it to this:
Observable.create (New Observableonsubscribe<integer> () {@OverridePublicvoid subscribe (ObservableEmitter <Integer> emitter) throws Exception {for (int i = 0;; i++) {//Infinite Loop event emitter.onnext (i);}} ). Subscribeon (Schedulers.io ()). Observeon (Androidschedulers.mainthread ()). Subscribe ( New Consumer<integer> () { @Override public void acceptthrows Exception {thread.sleep ( 2000); LOG.D (TAG,
This time the upstream switch to the IO thread, downstream to the main thread to receive, to see the results of the operation:
Violence.gif
As you can see, after adding a thread to the upstream, it's like a runaway Mustang, and the memory is blown out again.
Why not add threads and threads to differentiate so much, this involves the 同步
异步
knowledge of the.
When the upstream and downstream work in 同一个线程
, this is a 同步
subscription relationship, that is, 上游
each send an event 必须
wait until the 下游
receiving process is finished before the next event can be sent.
When the upstream and downstream work in 不同的线程
, this is a 异步
subscription relationship, this time to 上游
send data 不需要
waiting to 下游
receive, for what, because two threads are not able to communicate directly, so the event is not directly downstream to send a stream, This time will need a snail girl to help them, this snail girl is what we just said 水缸
! Upstream to send events to the tank, downstream from the tank to take the event to deal with, so when the upstream event speed too fast, downstream take the event speed is too slow, the tank will quickly fill, and then overflow out, In the end it was oom.
These two cases are represented by a picture as follows:
Synchronous:
Synchronize. png
Asynchronous:
Asynchronous. png
We can see that 同步和异步
the difference is only in whether there is 水缸
.
It is believed that through this example we have a clearer understanding of the communication between threads.
Source found, as long as there 水缸
, will appear upstream and downstream send event speed imbalance situation, so when we encounter backpressure, think carefully about where the tank, find the tank, you find a solution to the problem.
Now that the source has been found, we are going to learn how to solve it in the next section. See you in the next section.
Season_zlc
Links: http://www.jianshu.com/p/0f2d6c2387c9
Source: Pinterest
Copyright belongs to the author. Commercial reprint please contact the author for authorization, non-commercial reprint please specify the source.
RxJava2.0 Tutorial for Beginners (v) (ext.)