Original: Curly brace MC(wechat official account: Huakuohao-MC), welcome to share, please keep the source.

I admit this article has the suspicion of the headline party, read this article will not make you 20,000 yuan a month. If you want to earn 20,000 yuan a month or more, it is not by an article, a book, a project to achieve.

But a qualified programmer should have some knowledge of responsive programming, even a clear understanding of it.

Hopefully this article has given you a basic understanding of responsive programming, what benefits it brings, what problems it solves, and why it is important.

Responsive programming development process

The concept of responsive programming is a library originally proposed by Microsoft and implemented on the.NET platform. As the model became widely accepted, ReactiveX implemented libraries for many other languages, notably RXJava, for the Java language.

Later, ReactiveX and Reactor jointly developed Reactive Stream standard, and both ReactiveX and Reactor are implemented under this standard. Spring5 formally introduced Reactor and implemented web-flux based on the framework.

In addition, Java8 introduced Stream streams and lamada expressions, and Java9 introduced Flow, another support for responsive programming.

What is responsive programming

reactive programming is a declarative programming paradigm concerned with data streams and the propagation of change

This is the wikipedia definition of responsive programming. My assessment of this definition is that those who understand will understand, and those who do not understand will still not understand.

I’ll refine this definition’s keyword declarative, data flow, passing changes (responses), and add asynchro myself, because actually production level code responds asynchronously and rarely synchronously.

Before getting into reactive programming, let’s explain what these keywords mean.

Declarative programming

Declarative corresponds to directive. We are familiar with the instruction formula, which is to write each instruction to complete a task in turn.

For example, if you take a list of apples, and you find all the red apples, this is how directive programming works.

List<Apple> apples = new ArrayList<Apple>();

for (Apple apple : apples){
    if (apple.getColor() == "red"){ System.out.println(apple); }}Copy the code

Declarative programming, just write out what you want.

Select * from apple where color = red select * from apple where color = red

Simply put, declarative programming is chat programming, telling the computer what you want.

The data flow

Let’s talk about data flow. Actually, data flow can be thought of as a stream of data, events, signals, etc. If you are familiar with the Stream Stream introduced in Java8, it will make sense. If you do not know, you can do an introduction through my article.

Transfer change (response)

Transfer change (response), in fact, is the embodiment of the word response. A response is when you say hello to someone and they say hello back. Someone’s response to you is a response.

Mapping the above scenario to object-oriented programming is the Observer (subscription) pattern. The observer acts in response to certain behaviors of the observed.

While the observer pattern may be new to some front-end programmers, the familiar Ajax callback function is a manifestation of responsive programming, as shown in the following JS code

$.ajax("example.action")
    .done(function(){
        console.log("success")
    })
    .fail(function(){
        console.log("error")
    })
    .always(function(){
        console.log("complete")});Copy the code

This is typically an asynchronous callback, with one response action when the request succeeds and another response action when the request fails.

asynchronous

There are synchronous and asynchronous responses in terms of how to respond. In most practical applications, asynchronous responses are used.

Synchro: You call a travel agent to book a flight. The operator receives your call and looks up the flight information before making the reservation. You hold the phone waiting for his answer.

Asynchronous: You call a travel agent to book a flight, the operator gets the call, notes the flight information you want to book, and hangs up. When he has made the reservation, he will call you to tell you the result. That’s asynchrony.

Obviously asynchronous operations are more efficient for you because you don’t have to wait for the operator to do something, you can do something else.

The above scenario is also known by many as the Hollywood rule. Many good actors go to Hollywood to sign up for acting, the agency will register the name of the actor, and when there is a suitable opportunity, the agency will call the actor, instead of the actor has been waiting at the scene, or constantly call the agency to inquire. Don’t call me I will call you.

A profound

In fact, after introducing the above things, you may still have a vague understanding of responsive programming. Let’s take the Reactor framework as an example to make a simple illustration. After all, programmers love show me the code.

As mentioned above, the core of responsive programming is based on the observer (subscription) pattern. The observer observes the behavior of the observed and responds differently according to different behaviors.

Publisher is represented by two classes, Flux and Mono, in the Reactor framework. Flux 0… N element sequence; Mono stands for zero or a sequence of elements.

Flux/Mono can publish three types of values: normal value, abnormal signal, and complete signal. The three types of signals do not exist at the same time. At most, two types of signals can be issued simultaneously.

For example, let’s say Flux sends a stream of six integers ranging from 1 to 6, which is followed by a completion signal that tells the subscriber or observer that the data stream is complete. Similarly, if there is an exception in the process of sending normal data, an exception signal can also be sent to the subscriber or observer to indicate that there is an exception and the transmission will be stopped. An exception signal and a completion signal cannot exist together, because the data flow ends when either one is present. However, a signal flow can have neither an exception signal nor a completion signal, which means that the flow is an infinite flow.

Flux. Just (6)

This line of code shows that the publisher published six messages, and we subscribers responded to six messages.

Flux. Just (6). The subscribe (System. Out: : print)

On the console it will print 1,2,3,4,5,6.

Note that events or elements are only responded to when subscribed.

In the example above, we didn’t do anything to the elements or events, just printed them out as they were, which is obviously not what we wanted. Now let’s do something meaningful to the element.

The operator

map

Perform the map function once for each element in the data stream. The schematic diagram is as follows

Code sample

Flux.range(1.6).map(i -> i*i).subscribe(System.out::println);
Copy the code

It’s going to print 1, 4, 9, 16, 25, 36

flatmap

This operator logically consists of two operations, the first is the map operation and the second is flatten, which is similar to the merge operation. After mapping each element, flatten merges into a new flow. The schematic diagram is as follows.

Code sample

Flux.just("apple-1"."pear-2").flatMap(i -> 
Flux.fromArray(i.split("-"))).subscribe(System.out::println);
Copy the code

The code above will output Apple 1 PEAR 2;

filter

Filter out the elements that match the criteria.

Code sample

Flux.range(1.6).filter(i -> i>3).subscribe(System.out::println)
Copy the code

The above code will print 4,5, and 6

Zip zip is a zip code, used in Reactor, that combines two streams of data together. The schematic diagram is as follows.

The sample code

Flux.zip(       
    Flux.just("A"."B"."C"),
    Flux.just("1"."2"."3"),
    (x,y) -> x + y        
    ).subscribe(System.out::println);
Copy the code

The above code outputs A1, B2, and C3

There are many other operators that are not described here, but you can see the official website if you are interested.

Thread scheduling

Reactor naturally supports multithreading. And multithreaded scheduling is easy. Threads created in a Reactor are represented by the Scheduler interface.

// Create a thread
Scheduler single = Schedulers.single();
Copy the code
// Create threads equal to the number of CPU cores
Scheduler parallel = Schedulers.parallel();
Copy the code
// Create a bounded thread pool with 10 times the number of CPU cores by default
Scheduler elastic = Schedulers.boundedElastic();
Copy the code

Created threads, naturally to allocate threads, that is, thread scheduling. Switching thread context is mainly implemented through publishOn() and subscribeOn() functions.

PublishOn () affects what happens after the function is called. And subscribeOn() affects the entire chain of operations from the source, no matter where the subscribeOn() call occurs.

Here’s an example:

    Flux.just("hello")
    .map(s -> {
            System.out.println("[map] Thread name: " + Thread.currentThread().getName());
            return s.concat(" world!");
        })
    // Only change the thread after publishOn().
    .publishOn(Schedulers.newSingle("thread-publishOn"))
    .filter(s -> {
            System.out.println("[filter] Thread name: " + Thread.currentThread().getName());
            return s.startsWith("h");
        })
    // Change the entire operation chain thread from the source
    .subscribeOn(Schedulers.newSingle("thread-subscribeOn"))
    .subscribe(s -> {
                System.out.println("[subscribe] Thread name: " + Thread.currentThread().getName());
                System.out.println(s);
        });

Copy the code

The output of the code above looks like this

[map] Thread name: thread-subscribeOn-1
[filter] Thread name: thread-publishOn-2
[subscribe] Thread name: thread-publishOn-2
hello world!
Copy the code

I recommend that you copy the above code to run locally and comment out the subscribeOn() and publishOn() separately to feel the difference.

These two functions are often used when a blocking operation occurs, to schedule the blocking operation to a new thread for efficiency.

Response programming to solve what problems

Reactive programming can help solve two types of tricky problems: the familiar callback hell, and the inefficient synchronous blocking.

Let’s start with the first question. Using an official reactor example, find a user’s five favorite hobbies. This is done through Callback.

  1. Callback-based services use an anonymous nameCallbackAs a parameter. The latter two methods are called on success or exception of asynchronous execution, respectively.
  2. Access to theFavorite IDthelistCall the callback method of the first serviceonSuccess.
  3. iflistIf null, callsuggestionService.
  4. servicesuggestionServicepassList<Favorite>Give the second callback.
  5. Since it’s dealing withUI, we need to make sure that the consuming code runs inUIThreads.
  6. useJava 8 StreamTo limit the recommended number to 5 and then inUIIn the display.
  7. At each level, we handle errors the same way: in onepopupError information is displayed.
  8. Go back toFavorite IDThis layer, if I returnlistWe need to usefavoriteServiceIn order to getFavoriteObject. Since you only want 5, usestream
  9. Another pullback. This time for everyIDTo obtainFavoriteObjects in theUIThread push to the front end display.

Reactor responsive programming code would look something like this

  1. We getFavorite IDThe flow.
  2. We asynchronously convert them (ID) toFavoriteObject (usingflatMap), now we haveFavoriteFlow.
  3. Once theFavoriteIf empty, switch tosuggestionService.
  4. We focus on a maximum of five elements in the flow.
  5. And finally, we want to be inUIProcessing in the thread.
  6. By describing the final processing of the data (inUI) and error handling (shown inpopupIn) to trigger (subscribe).

You can see that by using reactive programming, the code is much more readable and the logic is clearer.

Turning to the second problem, synchronous blocking is generally considered inefficient. Asynchronous non-blocking is considered efficient. Reactive programming, by nature, is asynchronous and non-blocking.

Let’s take a simple example of why synchronous blocking is inefficient and asynchronous non-blocking is efficient.

Synchronous and asynchronous describe the ability of service providers to provide services. When a caller makes a request to a service provider, the service provider can immediately return and somehow notify the caller after processing it, which is asynchronous. Conversely, if the service provider returns only after the processing is complete, or requires the caller to actively query the results of the processing, it is synchronous.

Blocking and non-blocking describe the state of the caller. When a caller initiates a request to a service provider and waits for the result of the processing to return, it cannot perform subsequent operations, which is a blocked state. If the call returns directly, subsequent operations are non-blocking.

The phone call example mentioned above is an asynchronous non-blocking example. You call a travel agent and book a flight. The travel agent receives your request and immediately (asynchronously) replies telling you that the request has been received and that you will be notified later. Then you hang up the phone, go to something else (non-blocking), and the travel agent will call you as soon as the booking is made.

For synchronous blocking, the scenario would be something like this: you call the travel agent to book a flight, the operator answers your call and then processes the booking request, and you’re waiting on the other end of the line, doing nothing. To make matters worse, other passengers’ booking requests never come through because you keep taking up the line resources. What an inefficient way to deal with it.

conclusion

Although responsive programming is good, it is not a cure-all. It is difficult to master it at first. Meanwhile, debugging also requires some relevant experience. More importantly, it’s up to the business scenario to determine whether responsive programming really benefits us. Remember there are no silver bullets in software engineering.

Recommended reading

1. Java concurrent programming stuff (10) — Final summary

2. Common network problem locating tools that programmers should master

3. Do you know how to use Awk

4. Teach you how to build a set of ELK log search operation and maintenance platform

Original: Curly brace MC(wechat official account: Huakuohao-MC) Focus on JAVA basic programming and big data, focus on experience sharing and personal growth.